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;
|
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
|
// Set a ship action points, adding/updating an equipment if needed
|
||||||
static setShipAP(ship: Ship, points: number, recovery: number = 0): void {
|
static setShipAP(ship: Ship, points: number, recovery: number = 0): void {
|
||||||
var equipment = this.getOrGenEquipment(ship, SlotType.Power, new Equipments.BasicPowerCore());
|
var equipment = this.getOrGenEquipment(ship, SlotType.Power, new Equipments.BasicPowerCore());
|
||||||
|
|
|
@ -17,6 +17,9 @@ module SpaceTac.Game.AI {
|
||||||
// Time at which work as started
|
// Time at which work as started
|
||||||
started: number;
|
started: number;
|
||||||
|
|
||||||
|
// Random generator, if needed
|
||||||
|
random: RandomGenerator;
|
||||||
|
|
||||||
// Queue of work items to process
|
// Queue of work items to process
|
||||||
// Work items will be called successively, leaving time for other processing between them.
|
// Work items will be called successively, leaving time for other processing between them.
|
||||||
// So work items should always be as short as possible.
|
// So work items should always be as short as possible.
|
||||||
|
@ -29,6 +32,7 @@ module SpaceTac.Game.AI {
|
||||||
this.fleet = fleet;
|
this.fleet = fleet;
|
||||||
this.async = true;
|
this.async = true;
|
||||||
this.workqueue = [];
|
this.workqueue = [];
|
||||||
|
this.random = new RandomGenerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
postSerialize(fields: any): void {
|
postSerialize(fields: any): void {
|
||||||
|
|
|
@ -36,13 +36,18 @@ module SpaceTac.Game.AI {
|
||||||
protected initWork(): void {
|
protected initWork(): void {
|
||||||
this.addWorkItem(() => {
|
this.addWorkItem(() => {
|
||||||
var maneuvers = this.listAllManeuvers();
|
var maneuvers = this.listAllManeuvers();
|
||||||
|
var maneuver: BullyManeuver;
|
||||||
|
|
||||||
if (maneuvers.length > 0) {
|
if (maneuvers.length > 0) {
|
||||||
var maneuver = this.pickManeuver(maneuvers);
|
maneuver = this.pickManeuver(maneuvers);
|
||||||
this.applyManeuver(maneuver);
|
this.applyManeuver(maneuver);
|
||||||
|
|
||||||
// Try to make another maneuver
|
// Try to make another maneuver
|
||||||
this.initWork();
|
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;
|
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
|
// Check if a weapon can be used against an enemy
|
||||||
// Returns the BullyManeuver, or null if impossible to fire
|
// Returns the BullyManeuver, or null if impossible to fire
|
||||||
checkBullyManeuver(enemy: Ship, weapon: Equipment): BullyManeuver {
|
checkBullyManeuver(enemy: Ship, weapon: Equipment): BullyManeuver {
|
||||||
|
@ -98,12 +113,11 @@ module SpaceTac.Game.AI {
|
||||||
move = null;
|
move = null;
|
||||||
} else {
|
} else {
|
||||||
// Move to be in range, using first engine
|
// Move to be in range, using first engine
|
||||||
var engines = this.ship.listEquipment(SlotType.Engine);
|
engine = this.getEngine();
|
||||||
if (engines.length === 0) {
|
if (!engine) {
|
||||||
// No engine available to move
|
// No engine available to move
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
engine = engines[0];
|
|
||||||
var move_distance = distance - weapon.distance + this.move_margin;
|
var move_distance = distance - weapon.distance + this.move_margin;
|
||||||
var move_ap = engine.ap_usage * move_distance / engine.distance;
|
var move_ap = engine.ap_usage * move_distance / engine.distance;
|
||||||
if (move_ap > remaining_ap) {
|
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
|
// Pick a maneuver from a list of available ones
|
||||||
// By default, it chooses the nearest enemy
|
// By default, it chooses the nearest enemy
|
||||||
pickManeuver(available: BullyManeuver[]): BullyManeuver {
|
pickManeuver(available: BullyManeuver[]): BullyManeuver {
|
||||||
|
@ -153,9 +190,11 @@ module SpaceTac.Game.AI {
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addWorkItem(() => {
|
if (maneuver.fire) {
|
||||||
maneuver.fire.apply();
|
this.addWorkItem(() => {
|
||||||
}, 1500);
|
maneuver.fire.apply();
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
|
|
||||||
this.addWorkItem(null, 1500);
|
this.addWorkItem(null, 1500);
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,6 +163,38 @@ module SpaceTac.Game.AI.Specs {
|
||||||
expect(result.length).toBe(3);
|
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 () {
|
it("applies the chosen move", function () {
|
||||||
var battle = new Battle();
|
var battle = new Battle();
|
||||||
var ship1 = new Ship();
|
var ship1 = new Ship();
|
||||||
|
|
|
@ -9,7 +9,7 @@ module SpaceTac.Game.Equipments {
|
||||||
super(SlotType.Engine, "Conventional Engine");
|
super(SlotType.Engine, "Conventional Engine");
|
||||||
|
|
||||||
this.min_level = new IntegerRange(1, 1);
|
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.ap_usage = new Range(3);
|
||||||
|
|
||||||
this.addPermanentAttributeMaxEffect(AttributeCode.Initiative, 1);
|
this.addPermanentAttributeMaxEffect(AttributeCode.Initiative, 1);
|
||||||
|
|
|
@ -7,7 +7,7 @@ module SpaceTac.Game.Equipments {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("Gatling Gun", 50, 100);
|
super("Gatling Gun", 50, 100);
|
||||||
|
|
||||||
this.setRange(500, 500, false);
|
this.setRange(400, 400, false);
|
||||||
|
|
||||||
this.ap_usage = new Range(2, 3);
|
this.ap_usage = new Range(2, 3);
|
||||||
this.min_level = new IntegerRange(1, 3);
|
this.min_level = new IntegerRange(1, 3);
|
||||||
|
|
Loading…
Reference in a new issue