Made Bully AI move towards an enemy when no more maneuver is available
This commit is contained in:
parent
e0468338fd
commit
ef0756c0e0
|
@ -36,6 +36,13 @@ module SpaceTac.Game {
|
|||
return equipment;
|
||||
}
|
||||
|
||||
// Add an engine, allowing a ship to move *distance*, for each action points
|
||||
static addEngine(ship: Ship, distance: number): void {
|
||||
var equipment = this.getOrGenEquipment(ship, SlotType.Engine, new Equipments.ConventionalEngine());
|
||||
equipment.ap_usage = 1;
|
||||
equipment.distance = distance;
|
||||
}
|
||||
|
||||
// Set a ship action points, adding/updating an equipment if needed
|
||||
static setShipAP(ship: Ship, points: number, recovery: number = 0): void {
|
||||
var equipment = this.getOrGenEquipment(ship, SlotType.Power, new Equipments.BasicPowerCore());
|
||||
|
|
|
@ -17,6 +17,9 @@ module SpaceTac.Game.AI {
|
|||
// Time at which work as started
|
||||
started: number;
|
||||
|
||||
// Random generator, if needed
|
||||
random: RandomGenerator;
|
||||
|
||||
// Queue of work items to process
|
||||
// Work items will be called successively, leaving time for other processing between them.
|
||||
// So work items should always be as short as possible.
|
||||
|
@ -29,6 +32,7 @@ module SpaceTac.Game.AI {
|
|||
this.fleet = fleet;
|
||||
this.async = true;
|
||||
this.workqueue = [];
|
||||
this.random = new RandomGenerator();
|
||||
}
|
||||
|
||||
postSerialize(fields: any): void {
|
||||
|
|
|
@ -36,13 +36,18 @@ module SpaceTac.Game.AI {
|
|||
protected initWork(): void {
|
||||
this.addWorkItem(() => {
|
||||
var maneuvers = this.listAllManeuvers();
|
||||
var maneuver: BullyManeuver;
|
||||
|
||||
if (maneuvers.length > 0) {
|
||||
var maneuver = this.pickManeuver(maneuvers);
|
||||
maneuver = this.pickManeuver(maneuvers);
|
||||
this.applyManeuver(maneuver);
|
||||
|
||||
// Try to make another maneuver
|
||||
this.initWork();
|
||||
} else {
|
||||
// No bullying available, going to fallback move
|
||||
maneuver = this.getFallbackManeuver();
|
||||
this.applyManeuver(maneuver);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -84,6 +89,16 @@ module SpaceTac.Game.AI {
|
|||
return result;
|
||||
}
|
||||
|
||||
// Get an equipped engine to make a move
|
||||
getEngine(): Equipment {
|
||||
var engines = this.ship.listEquipment(SlotType.Engine);
|
||||
if (engines.length === 0) {
|
||||
return null;
|
||||
} else {
|
||||
return engines[0];
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a weapon can be used against an enemy
|
||||
// Returns the BullyManeuver, or null if impossible to fire
|
||||
checkBullyManeuver(enemy: Ship, weapon: Equipment): BullyManeuver {
|
||||
|
@ -98,12 +113,11 @@ module SpaceTac.Game.AI {
|
|||
move = null;
|
||||
} else {
|
||||
// Move to be in range, using first engine
|
||||
var engines = this.ship.listEquipment(SlotType.Engine);
|
||||
if (engines.length === 0) {
|
||||
engine = this.getEngine();
|
||||
if (!engine) {
|
||||
// No engine available to move
|
||||
return null;
|
||||
} else {
|
||||
engine = engines[0];
|
||||
var move_distance = distance - weapon.distance + this.move_margin;
|
||||
var move_ap = engine.ap_usage * move_distance / engine.distance;
|
||||
if (move_ap > remaining_ap) {
|
||||
|
@ -130,6 +144,29 @@ module SpaceTac.Game.AI {
|
|||
}
|
||||
}
|
||||
|
||||
// When no bully action is available, pick a random enemy, and go towards it
|
||||
getFallbackManeuver(): BullyManeuver {
|
||||
var enemies = this.listAllEnemies();
|
||||
if (enemies.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var MIN_DISTANCE = 20;
|
||||
var APPROACH_FACTOR = 0.5;
|
||||
|
||||
var picked = this.random.choice(enemies);
|
||||
var target = Target.newFromShip(picked);
|
||||
var distance = target.getDistanceTo(Target.newFromShip(this.ship));
|
||||
var engine = this.getEngine();
|
||||
if (distance > MIN_DISTANCE) { // Don't move too close
|
||||
target = target.constraintInRange(this.ship.arena_x, this.ship.arena_y, (distance - MIN_DISTANCE) * APPROACH_FACTOR);
|
||||
target = engine.action.checkLocationTarget(this.fleet.battle, this.ship, target);
|
||||
return new BullyManeuver(new Maneuver(this.ship, engine, target));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Pick a maneuver from a list of available ones
|
||||
// By default, it chooses the nearest enemy
|
||||
pickManeuver(available: BullyManeuver[]): BullyManeuver {
|
||||
|
@ -153,9 +190,11 @@ module SpaceTac.Game.AI {
|
|||
}, 500);
|
||||
}
|
||||
|
||||
this.addWorkItem(() => {
|
||||
maneuver.fire.apply();
|
||||
}, 1500);
|
||||
if (maneuver.fire) {
|
||||
this.addWorkItem(() => {
|
||||
maneuver.fire.apply();
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
this.addWorkItem(null, 1500);
|
||||
}
|
||||
|
|
|
@ -163,6 +163,38 @@ module SpaceTac.Game.AI.Specs {
|
|||
expect(result.length).toBe(3);
|
||||
});
|
||||
|
||||
it("gets a fallback maneuver", function () {
|
||||
var battle = TestTools.createBattle(1, 3);
|
||||
var ai = new BullyAI(battle.fleets[0]);
|
||||
ai.async = false;
|
||||
ai.ship = battle.fleets[0].ships[0];
|
||||
|
||||
TestTools.setShipAP(ai.ship, 5);
|
||||
TestTools.addEngine(ai.ship, 100);
|
||||
|
||||
var maneuver: BullyManeuver;
|
||||
|
||||
battle.fleets[1].ships.forEach((ship: Ship) => {
|
||||
ai.ship.setArenaPosition(0, 0);
|
||||
});
|
||||
|
||||
// Too much near an enemy, don't move
|
||||
ai.ship.setArenaPosition(10, 0);
|
||||
maneuver = ai.getFallbackManeuver();
|
||||
expect(maneuver).toBeNull();
|
||||
ai.ship.setArenaPosition(20, 0);
|
||||
maneuver = ai.getFallbackManeuver();
|
||||
expect(maneuver).toBeNull();
|
||||
|
||||
// Move towards an enemy (up to minimal distance)
|
||||
ai.ship.setArenaPosition(30, 0);
|
||||
maneuver = ai.getFallbackManeuver();
|
||||
expect(maneuver.move.target).toEqual(Target.newFromLocation(25, 0));
|
||||
ai.ship.setArenaPosition(25, 0);
|
||||
maneuver = ai.getFallbackManeuver();
|
||||
expect(maneuver.move.target).toEqual(Target.newFromLocation(22.5, 0));
|
||||
});
|
||||
|
||||
it("applies the chosen move", function () {
|
||||
var battle = new Battle();
|
||||
var ship1 = new Ship();
|
||||
|
|
|
@ -9,7 +9,7 @@ module SpaceTac.Game.Equipments {
|
|||
super(SlotType.Engine, "Conventional Engine");
|
||||
|
||||
this.min_level = new IntegerRange(1, 1);
|
||||
this.distance = new Range(500, 500);
|
||||
this.distance = new Range(300, 300);
|
||||
this.ap_usage = new Range(3);
|
||||
|
||||
this.addPermanentAttributeMaxEffect(AttributeCode.Initiative, 1);
|
||||
|
|
|
@ -7,7 +7,7 @@ module SpaceTac.Game.Equipments {
|
|||
constructor() {
|
||||
super("Gatling Gun", 50, 100);
|
||||
|
||||
this.setRange(500, 500, false);
|
||||
this.setRange(400, 400, false);
|
||||
|
||||
this.ap_usage = new Range(2, 3);
|
||||
this.min_level = new IntegerRange(1, 3);
|
||||
|
|
Loading…
Reference in New Issue