1
0
Fork 0

Made Bully AI move towards an enemy when no more maneuver is available

This commit is contained in:
Michaël Lemaire 2015-04-15 02:00:00 +02:00
parent e0468338fd
commit ef0756c0e0
6 changed files with 91 additions and 9 deletions

View File

@ -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());

View File

@ -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 {

View File

@ -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);
}

View File

@ -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();

View File

@ -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);

View File

@ -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);