Removed Bully AI and fixed AI trying unavailable actions
This commit is contained in:
parent
a3df49ae0b
commit
b10725abda
1
TODO
1
TODO
|
@ -47,6 +47,7 @@
|
||||||
* AI: add combination of random small move and actual maneuver, as producer
|
* AI: add combination of random small move and actual maneuver, as producer
|
||||||
* AI: evaluate based on simulated list of effects
|
* AI: evaluate based on simulated list of effects
|
||||||
* AI: consider overheat/cooldown
|
* AI: consider overheat/cooldown
|
||||||
|
* AI: new duel page with producers/evaluators tweaking
|
||||||
* Map: remove jump links that cross the radius of other systems
|
* Map: remove jump links that cross the radius of other systems
|
||||||
* Map: disable interaction (zoom, selection) while moving/jumping
|
* Map: disable interaction (zoom, selection) while moving/jumping
|
||||||
* Tutorial
|
* Tutorial
|
||||||
|
|
|
@ -107,7 +107,7 @@ module TS.SpaceTac {
|
||||||
*/
|
*/
|
||||||
static setup(element: HTMLElement) {
|
static setup(element: HTMLElement) {
|
||||||
let fakeship = new Ship();
|
let fakeship = new Ship();
|
||||||
let ais = [new BullyAI(fakeship), new TacticalAI(fakeship), new AbstractAI(fakeship)];
|
let ais = [new TacticalAI(fakeship), new AbstractAI(fakeship)];
|
||||||
ais.forEach((ai, idx) => {
|
ais.forEach((ai, idx) => {
|
||||||
let selects = element.getElementsByTagName("select");
|
let selects = element.getElementsByTagName("select");
|
||||||
for (let i = 0; i < selects.length; i++) {
|
for (let i = 0; i < selects.length; i++) {
|
||||||
|
|
|
@ -1,243 +0,0 @@
|
||||||
module TS.SpaceTac.Specs {
|
|
||||||
describe("BullyAI", function () {
|
|
||||||
it("lists enemies", function () {
|
|
||||||
var battle = new Battle();
|
|
||||||
battle.fleets[0].addShip(new Ship(null, "0-0"));
|
|
||||||
battle.fleets[1].addShip(new Ship(null, "1-0"));
|
|
||||||
battle.fleets[1].addShip(new Ship(null, "1-1"));
|
|
||||||
iforeach(battle.iships(), ship => ship.setAttribute("initiative", 1));
|
|
||||||
|
|
||||||
var random = new SkewedRandomGenerator([0, 0.5, 1]);
|
|
||||||
battle.throwInitiative(random);
|
|
||||||
|
|
||||||
var ai = new BullyAI(battle.fleets[0].ships[0], Timer.synchronous);
|
|
||||||
|
|
||||||
var result = ai.listAllEnemies();
|
|
||||||
expect(result).toEqual([battle.fleets[1].ships[1], battle.fleets[1].ships[0]]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("lists weapons", function () {
|
|
||||||
var ship = new Ship();
|
|
||||||
|
|
||||||
var ai = new BullyAI(ship, Timer.synchronous);
|
|
||||||
ai.ship = ship;
|
|
||||||
|
|
||||||
var result = ai.listAllWeapons();
|
|
||||||
expect(result.length).toBe(0);
|
|
||||||
|
|
||||||
var weapon1 = new Equipment(SlotType.Weapon, "weapon1");
|
|
||||||
weapon1.action = new FireWeaponAction(weapon1, 1, 1, 1, [new DamageEffect(50)]);
|
|
||||||
ai.ship.addSlot(SlotType.Weapon).attach(weapon1);
|
|
||||||
var weapon2 = new Equipment(SlotType.Weapon, "weapon2");
|
|
||||||
weapon2.action = new FireWeaponAction(weapon1, 1, 1, 1, [new DamageEffect(100)]);
|
|
||||||
ai.ship.addSlot(SlotType.Weapon).attach(weapon2);
|
|
||||||
var weapon3 = new Equipment(SlotType.Weapon, "weapon3");
|
|
||||||
ai.ship.addSlot(SlotType.Weapon).attach(weapon3);
|
|
||||||
|
|
||||||
ai.ship.addSlot(SlotType.Shield).attach(new Equipment(SlotType.Shield));
|
|
||||||
|
|
||||||
result = ai.listAllWeapons();
|
|
||||||
expect(result).toEqual([weapon1, weapon2]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("checks a firing possibility", function () {
|
|
||||||
var ship = new Ship();
|
|
||||||
let engine = TestTools.addEngine(ship, 1 / 3);
|
|
||||||
TestTools.setShipAP(ship, 10);
|
|
||||||
var enemy = new Ship();
|
|
||||||
var ai = new BullyAI(ship, Timer.synchronous);
|
|
||||||
ai.ship = ship;
|
|
||||||
ai.move_margin = 0;
|
|
||||||
let weapon = TestTools.addWeapon(ship, 0, 2, 3);
|
|
||||||
|
|
||||||
// enemy in range, the ship can fire without moving
|
|
||||||
ship.values.power.set(8);
|
|
||||||
ship.arena_x = 1;
|
|
||||||
ship.arena_y = 0;
|
|
||||||
enemy.arena_x = 3;
|
|
||||||
enemy.arena_y = 0;
|
|
||||||
var result = ai.checkBullyManeuver(enemy, weapon);
|
|
||||||
if (result) {
|
|
||||||
expect(result.simulation.need_move).toBe(false);
|
|
||||||
expect(result.simulation.fire_location).toEqual(Target.newFromShip(enemy));
|
|
||||||
expect(result.equipment).toBe(weapon);
|
|
||||||
} else {
|
|
||||||
fail("No maneuver proposed");
|
|
||||||
}
|
|
||||||
|
|
||||||
// enemy out of range, but moving can bring it in range
|
|
||||||
ship.values.power.set(8);
|
|
||||||
ship.arena_x = 1;
|
|
||||||
ship.arena_y = 0;
|
|
||||||
enemy.arena_x = 6;
|
|
||||||
enemy.arena_y = 0;
|
|
||||||
result = ai.checkBullyManeuver(enemy, weapon);
|
|
||||||
if (result) {
|
|
||||||
expect(result.simulation.move_location).toEqual(Target.newFromLocation(3, 0));
|
|
||||||
expect(result.simulation.fire_location).toEqual(Target.newFromShip(enemy));
|
|
||||||
expect(result.equipment).toBe(weapon);
|
|
||||||
} else {
|
|
||||||
fail("No maneuver proposed");
|
|
||||||
}
|
|
||||||
|
|
||||||
// enemy out of range, but moving can bring it in range, except for the safety margin
|
|
||||||
ai.move_margin = 0.1;
|
|
||||||
ship.values.power.set(8);
|
|
||||||
ship.arena_x = 1;
|
|
||||||
ship.arena_y = 0;
|
|
||||||
enemy.arena_x = 6;
|
|
||||||
enemy.arena_y = 0;
|
|
||||||
result = ai.checkBullyManeuver(enemy, weapon);
|
|
||||||
expect(result).toBeNull();
|
|
||||||
ai.move_margin = 0;
|
|
||||||
|
|
||||||
// enemy totally out of range
|
|
||||||
ship.values.power.set(8);
|
|
||||||
ship.arena_x = 1;
|
|
||||||
ship.arena_y = 0;
|
|
||||||
enemy.arena_x = 30;
|
|
||||||
enemy.arena_y = 0;
|
|
||||||
result = ai.checkBullyManeuver(enemy, weapon);
|
|
||||||
expect(result).toBeNull();
|
|
||||||
|
|
||||||
// enemy in range but not enough AP to fire
|
|
||||||
ship.values.power.set(1);
|
|
||||||
ship.arena_x = 1;
|
|
||||||
ship.arena_y = 0;
|
|
||||||
enemy.arena_x = 3;
|
|
||||||
enemy.arena_y = 0;
|
|
||||||
result = ai.checkBullyManeuver(enemy, weapon);
|
|
||||||
expect(result).toBeNull();
|
|
||||||
|
|
||||||
// can move in range of enemy, but not enough AP to fire
|
|
||||||
ship.values.power.set(7);
|
|
||||||
ship.arena_x = 1;
|
|
||||||
ship.arena_y = 0;
|
|
||||||
enemy.arena_x = 6;
|
|
||||||
enemy.arena_y = 0;
|
|
||||||
result = ai.checkBullyManeuver(enemy, weapon);
|
|
||||||
expect(result).toBeNull();
|
|
||||||
|
|
||||||
// no engine, can't move
|
|
||||||
engine.detach();
|
|
||||||
ship.values.power.set(8);
|
|
||||||
ship.arena_x = 1;
|
|
||||||
ship.arena_y = 0;
|
|
||||||
enemy.arena_x = 6;
|
|
||||||
enemy.arena_y = 0;
|
|
||||||
result = ai.checkBullyManeuver(enemy, weapon);
|
|
||||||
expect(result).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("lists available firing actions", function () {
|
|
||||||
var battle = new Battle();
|
|
||||||
var ship1 = new Ship();
|
|
||||||
ship1.setArenaPosition(3, 2);
|
|
||||||
battle.fleets[0].addShip(ship1);
|
|
||||||
var ship2 = new Ship();
|
|
||||||
ship2.setArenaPosition(5, 3);
|
|
||||||
battle.fleets[1].addShip(ship2);
|
|
||||||
var ship3 = new Ship();
|
|
||||||
ship3.setArenaPosition(11, 15);
|
|
||||||
battle.fleets[1].addShip(ship3);
|
|
||||||
battle.throwInitiative(new SkewedRandomGenerator([1, 0.5, 0]));
|
|
||||||
|
|
||||||
var ai = new BullyAI(ship1, Timer.synchronous);
|
|
||||||
ai.ship = ship1;
|
|
||||||
|
|
||||||
var result = ai.listAllManeuvers();
|
|
||||||
expect(result.length).toBe(0);
|
|
||||||
|
|
||||||
TestTools.setShipAP(ai.ship, 8);
|
|
||||||
let weapon1 = TestTools.addWeapon(ai.ship, 10, 1, 50);
|
|
||||||
let weapon2 = TestTools.addWeapon(ai.ship, 5, 1, 10);
|
|
||||||
|
|
||||||
result = ai.listAllManeuvers();
|
|
||||||
expect(result.length).toBe(3);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("gets a fallback maneuver", function () {
|
|
||||||
var battle = TestTools.createBattle(1, 3);
|
|
||||||
var ai = new BullyAI(battle.fleets[0].ships[0], Timer.synchronous);
|
|
||||||
|
|
||||||
TestTools.setShipAP(ai.ship, 5);
|
|
||||||
var engine = TestTools.addEngine(ai.ship, 100);
|
|
||||||
(<MoveAction>engine.action).safety_distance = 20;
|
|
||||||
|
|
||||||
var maneuver: BullyManeuver | null;
|
|
||||||
|
|
||||||
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();
|
|
||||||
if (maneuver) {
|
|
||||||
expect(maneuver.simulation.move_location).toEqual(Target.newFromLocation(25, 0));
|
|
||||||
} else {
|
|
||||||
fail("No maneuver proposed");
|
|
||||||
}
|
|
||||||
ai.ship.setArenaPosition(25, 0);
|
|
||||||
maneuver = ai.getFallbackManeuver();
|
|
||||||
if (maneuver) {
|
|
||||||
expect(maneuver.simulation.move_location).toEqual(Target.newFromLocation(22.5, 0));
|
|
||||||
} else {
|
|
||||||
fail("No maneuver proposed");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it("applies the chosen move", function () {
|
|
||||||
var battle = new Battle();
|
|
||||||
var ship1 = new Ship();
|
|
||||||
ship1.setArenaPosition(0, 0);
|
|
||||||
battle.fleets[0].addShip(ship1);
|
|
||||||
var ship2 = new Ship();
|
|
||||||
ship2.setArenaPosition(8, 0);
|
|
||||||
battle.fleets[1].addShip(ship2);
|
|
||||||
|
|
||||||
var ai = new BullyAI(ship1, Timer.synchronous);
|
|
||||||
ai.move_margin = 0;
|
|
||||||
|
|
||||||
var engine = new Equipment(SlotType.Engine);
|
|
||||||
engine.action = new MoveAction(engine, 0.5);
|
|
||||||
ai.ship.addSlot(SlotType.Engine).attach(engine);
|
|
||||||
|
|
||||||
var weapon = new Equipment(SlotType.Weapon);
|
|
||||||
weapon.action = new FireWeaponAction(weapon, 1, 6, 0, [new DamageEffect(20)]);
|
|
||||||
ai.ship.addSlot(SlotType.Weapon).attach(weapon);
|
|
||||||
|
|
||||||
ai.ship.values.power.setMaximal(10);
|
|
||||||
ai.ship.values.power.set(6);
|
|
||||||
|
|
||||||
ship2.values.hull.set(15);
|
|
||||||
ship2.values.shield.set(10);
|
|
||||||
|
|
||||||
var move = ai.checkBullyManeuver(ship2, weapon);
|
|
||||||
expect(move).not.toBeNull();
|
|
||||||
|
|
||||||
battle.playing_ship = ai.ship;
|
|
||||||
battle.log.clear();
|
|
||||||
ai.applyManeuver(move);
|
|
||||||
|
|
||||||
expect(battle.log.events.length).toBe(7);
|
|
||||||
|
|
||||||
expect(battle.log.events[0]).toEqual(new ValueChangeEvent(ship1, new ShipValue("power", 2, 10), -4));
|
|
||||||
expect(battle.log.events[1]).toEqual(new MoveEvent(ship1, 2, 0));
|
|
||||||
|
|
||||||
expect(battle.log.events[2]).toEqual(new ValueChangeEvent(ship1, new ShipValue("power", 1, 10), -1));
|
|
||||||
expect(battle.log.events[3]).toEqual(new FireEvent(ship1, weapon, Target.newFromShip(ship2)));
|
|
||||||
expect(battle.log.events[4]).toEqual(new ValueChangeEvent(ship2, new ShipValue("shield", 0), -10));
|
|
||||||
expect(battle.log.events[5]).toEqual(new ValueChangeEvent(ship2, new ShipValue("hull", 5), -10));
|
|
||||||
expect(battle.log.events[6]).toEqual(new DamageEvent(ship2, 10, 10));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,158 +0,0 @@
|
||||||
/// <reference path="AbstractAI.ts"/>
|
|
||||||
/// <reference path="Maneuver.ts"/>
|
|
||||||
module TS.SpaceTac {
|
|
||||||
export class BullyManeuver extends Maneuver {
|
|
||||||
// Get a sorting score, by distance to another point
|
|
||||||
// Nearest means higher score
|
|
||||||
getScoreByDistance(point: Target): number {
|
|
||||||
return -point.getDistanceTo(this.simulation.fire_location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Basic Artificial Intelligence, with a tendency to move forward and shoot the nearest enemy
|
|
||||||
export class BullyAI extends AbstractAI {
|
|
||||||
// Safety margin in moves to account for floating-point rounding errors
|
|
||||||
move_margin = 0.1;
|
|
||||||
|
|
||||||
protected initWork(): void {
|
|
||||||
if (this.ship.getValue("power") > 0) {
|
|
||||||
this.addWorkItem(() => {
|
|
||||||
var maneuvers = this.listAllManeuvers();
|
|
||||||
var maneuver: BullyManeuver | null;
|
|
||||||
|
|
||||||
if (maneuvers.length > 0) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// List all enemy ships that can be a target
|
|
||||||
listAllEnemies(): Ship[] {
|
|
||||||
var result: Ship[] = [];
|
|
||||||
|
|
||||||
let battle = this.ship.getBattle();
|
|
||||||
if (battle) {
|
|
||||||
battle.play_order.forEach((ship: Ship) => {
|
|
||||||
if (ship.alive && ship.getPlayer() !== this.ship.getPlayer()) {
|
|
||||||
result.push(ship);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// List all weapons
|
|
||||||
listAllWeapons(): Equipment[] {
|
|
||||||
return this.ship.listEquipment(SlotType.Weapon).filter(equipement => equipement.action instanceof FireWeaponAction && any(equipement.action.effects, effect => effect instanceof DamageEffect));
|
|
||||||
}
|
|
||||||
|
|
||||||
// List all available maneuvers for the playing ship
|
|
||||||
listAllManeuvers(): BullyManeuver[] {
|
|
||||||
var result: BullyManeuver[] = [];
|
|
||||||
|
|
||||||
var enemies = this.listAllEnemies();
|
|
||||||
var weapons = this.listAllWeapons();
|
|
||||||
|
|
||||||
enemies.forEach((ship: Ship) => {
|
|
||||||
weapons.forEach((weapon: Equipment) => {
|
|
||||||
var maneuver = this.checkBullyManeuver(ship, weapon);
|
|
||||||
if (maneuver) {
|
|
||||||
result.push(maneuver);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get an equipped engine to make a move
|
|
||||||
getEngine(): Equipment | null {
|
|
||||||
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 | null {
|
|
||||||
let maneuver = new BullyManeuver(this.ship, weapon, Target.newFromShip(enemy), this.move_margin);
|
|
||||||
// TODO In case of blast weapon, check that this would be a hit !
|
|
||||||
if (maneuver.simulation.can_fire) {
|
|
||||||
return maneuver;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// When no bully action is available, pick a random enemy, and go towards it
|
|
||||||
getFallbackManeuver(): BullyManeuver | null {
|
|
||||||
var enemies = this.listAllEnemies();
|
|
||||||
if (enemies.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (engine) {
|
|
||||||
var safety_distance = (<MoveAction>engine.action).safety_distance;
|
|
||||||
if (distance > safety_distance) { // Don't move too close
|
|
||||||
target = target.constraintInRange(this.ship.arena_x, this.ship.arena_y,
|
|
||||||
(distance - safety_distance) * APPROACH_FACTOR);
|
|
||||||
let loctarget = engine.action.checkLocationTarget(this.ship, target);
|
|
||||||
if (loctarget) {
|
|
||||||
return new BullyManeuver(this.ship, engine, loctarget);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pick a maneuver from a list of available ones
|
|
||||||
// By default, it chooses the nearest enemy
|
|
||||||
pickManeuver(available: BullyManeuver[]): BullyManeuver | null {
|
|
||||||
if (available.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort by descending score
|
|
||||||
available.sort((m1: BullyManeuver, m2: BullyManeuver): number => {
|
|
||||||
var point = Target.newFromShip(this.ship);
|
|
||||||
return m1.getScoreByDistance(point) < m2.getScoreByDistance(point) ? 1 : -1;
|
|
||||||
});
|
|
||||||
return available[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Effectively apply the chosen maneuver
|
|
||||||
applyManeuver(maneuver: BullyManeuver | null): void {
|
|
||||||
if (maneuver) {
|
|
||||||
this.addWorkItem(() => {
|
|
||||||
maneuver.apply();
|
|
||||||
}, 1500);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.addWorkItem(null, 1500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,14 +2,14 @@ module TS.SpaceTac {
|
||||||
/**
|
/**
|
||||||
* Ship maneuver for an artifical intelligence
|
* Ship maneuver for an artifical intelligence
|
||||||
*
|
*
|
||||||
* A maneuver is like a human player action, choosing an equipment and using it
|
* A maneuver is like a human player action, choosing an action and using it
|
||||||
*/
|
*/
|
||||||
export class Maneuver {
|
export class Maneuver {
|
||||||
// Concerned ship
|
// Concerned ship
|
||||||
ship: Ship;
|
ship: Ship;
|
||||||
|
|
||||||
// Equipment to use
|
// Action to use
|
||||||
equipment: Equipment;
|
action: BaseAction;
|
||||||
|
|
||||||
// Target for the action;
|
// Target for the action;
|
||||||
target: Target;
|
target: Target;
|
||||||
|
@ -17,17 +17,17 @@ module TS.SpaceTac {
|
||||||
// Result of move-fire simulation
|
// Result of move-fire simulation
|
||||||
simulation: MoveFireResult;
|
simulation: MoveFireResult;
|
||||||
|
|
||||||
constructor(ship: Ship, equipment: Equipment, target: Target, move_margin = 0.1) {
|
constructor(ship: Ship, action: BaseAction, target: Target, move_margin = 0.1) {
|
||||||
this.ship = ship;
|
this.ship = ship;
|
||||||
this.equipment = equipment;
|
this.action = action;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
|
|
||||||
let simulator = new MoveFireSimulator(this.ship);
|
let simulator = new MoveFireSimulator(this.ship);
|
||||||
this.simulation = simulator.simulateAction(this.equipment.action, this.target, move_margin);
|
this.simulation = simulator.simulateAction(this.action, this.target, move_margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
jasmineToString() {
|
jasmineToString() {
|
||||||
return `Use ${this.equipment.jasmineToString()} on ${this.target.jasmineToString()}`;
|
return `Use ${this.action.code} on ${this.target.jasmineToString()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,7 +5,7 @@ module TS.SpaceTac.Specs {
|
||||||
class FixedManeuver extends Maneuver {
|
class FixedManeuver extends Maneuver {
|
||||||
score: number;
|
score: number;
|
||||||
constructor(score: number) {
|
constructor(score: number) {
|
||||||
super(new Ship(), new Equipment(), new Target(0, 0));
|
super(new Ship(), new BaseAction("nothing", "Do nothing", true), new Target(0, 0));
|
||||||
this.score = score;
|
this.score = score;
|
||||||
}
|
}
|
||||||
apply() {
|
apply() {
|
||||||
|
|
|
@ -7,6 +7,9 @@ module TS.SpaceTac.Specs {
|
||||||
let ship1a = battle.fleets[1].addShip(new Ship(null, "1A"));
|
let ship1a = battle.fleets[1].addShip(new Ship(null, "1A"));
|
||||||
let ship1b = battle.fleets[1].addShip(new Ship(null, "1B"));
|
let ship1b = battle.fleets[1].addShip(new Ship(null, "1B"));
|
||||||
|
|
||||||
|
TestTools.setShipAP(ship0a, 10);
|
||||||
|
battle.playing_ship = ship0a;
|
||||||
|
|
||||||
let result = imaterialize(TacticalAIHelpers.produceDirectShots(ship0a, battle));
|
let result = imaterialize(TacticalAIHelpers.produceDirectShots(ship0a, battle));
|
||||||
expect(result.length).toBe(0);
|
expect(result.length).toBe(0);
|
||||||
|
|
||||||
|
@ -14,10 +17,10 @@ module TS.SpaceTac.Specs {
|
||||||
let weapon2 = TestTools.addWeapon(ship0a, 15);
|
let weapon2 = TestTools.addWeapon(ship0a, 15);
|
||||||
result = imaterialize(TacticalAIHelpers.produceDirectShots(ship0a, battle));
|
result = imaterialize(TacticalAIHelpers.produceDirectShots(ship0a, battle));
|
||||||
expect(result.length).toBe(4);
|
expect(result.length).toBe(4);
|
||||||
expect(result).toContain(new Maneuver(ship0a, weapon1, Target.newFromShip(ship1a)));
|
expect(result).toContain(new Maneuver(ship0a, weapon1.action, Target.newFromShip(ship1a)));
|
||||||
expect(result).toContain(new Maneuver(ship0a, weapon1, Target.newFromShip(ship1b)));
|
expect(result).toContain(new Maneuver(ship0a, weapon1.action, Target.newFromShip(ship1b)));
|
||||||
expect(result).toContain(new Maneuver(ship0a, weapon2, Target.newFromShip(ship1a)));
|
expect(result).toContain(new Maneuver(ship0a, weapon2.action, Target.newFromShip(ship1a)));
|
||||||
expect(result).toContain(new Maneuver(ship0a, weapon2, Target.newFromShip(ship1b)));
|
expect(result).toContain(new Maneuver(ship0a, weapon2.action, Target.newFromShip(ship1b)));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("produces random moves inside a grid", function () {
|
it("produces random moves inside a grid", function () {
|
||||||
|
@ -26,17 +29,20 @@ module TS.SpaceTac.Specs {
|
||||||
battle.height = 100;
|
battle.height = 100;
|
||||||
let ship = battle.fleets[0].addShip();
|
let ship = battle.fleets[0].addShip();
|
||||||
|
|
||||||
|
TestTools.setShipAP(ship, 10);
|
||||||
|
battle.playing_ship = ship;
|
||||||
|
|
||||||
let result = imaterialize(TacticalAIHelpers.produceRandomMoves(ship, battle, 2, 1));
|
let result = imaterialize(TacticalAIHelpers.produceRandomMoves(ship, battle, 2, 1));
|
||||||
expect(result.length).toBe(0);
|
expect(result.length).toBe(0);
|
||||||
|
|
||||||
let engine = ship.addSlot(SlotType.Engine).attach(new Equipment(SlotType.Engine));
|
let engine = TestTools.addEngine(ship, 1000);
|
||||||
|
|
||||||
result = imaterialize(TacticalAIHelpers.produceRandomMoves(ship, battle, 2, 1, new SkewedRandomGenerator([0.5], true)));
|
result = imaterialize(TacticalAIHelpers.produceRandomMoves(ship, battle, 2, 1, new SkewedRandomGenerator([0.5], true)));
|
||||||
expect(result).toEqual([
|
expect(result).toEqual([
|
||||||
new Maneuver(ship, engine, Target.newFromLocation(25, 25)),
|
new Maneuver(ship, engine.action, Target.newFromLocation(25, 25)),
|
||||||
new Maneuver(ship, engine, Target.newFromLocation(75, 25)),
|
new Maneuver(ship, engine.action, Target.newFromLocation(75, 25)),
|
||||||
new Maneuver(ship, engine, Target.newFromLocation(25, 75)),
|
new Maneuver(ship, engine.action, Target.newFromLocation(25, 75)),
|
||||||
new Maneuver(ship, engine, Target.newFromLocation(75, 75)),
|
new Maneuver(ship, engine.action, Target.newFromLocation(75, 75)),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -45,6 +51,9 @@ module TS.SpaceTac.Specs {
|
||||||
let ship = battle.fleets[0].addShip();
|
let ship = battle.fleets[0].addShip();
|
||||||
let weapon = TestTools.addWeapon(ship, 50, 1, 1000, 105);
|
let weapon = TestTools.addWeapon(ship, 50, 1, 1000, 105);
|
||||||
|
|
||||||
|
TestTools.setShipAP(ship, 10);
|
||||||
|
battle.playing_ship = ship;
|
||||||
|
|
||||||
let result = imaterialize(TacticalAIHelpers.produceBlastShots(ship, battle));
|
let result = imaterialize(TacticalAIHelpers.produceBlastShots(ship, battle));
|
||||||
expect(result.length).toBe(0);
|
expect(result.length).toBe(0);
|
||||||
|
|
||||||
|
@ -59,8 +68,8 @@ module TS.SpaceTac.Specs {
|
||||||
|
|
||||||
result = imaterialize(TacticalAIHelpers.produceBlastShots(ship, battle));
|
result = imaterialize(TacticalAIHelpers.produceBlastShots(ship, battle));
|
||||||
expect(result).toEqual([
|
expect(result).toEqual([
|
||||||
new Maneuver(ship, weapon, Target.newFromLocation(600, 0)),
|
new Maneuver(ship, weapon.action, Target.newFromLocation(600, 0)),
|
||||||
new Maneuver(ship, weapon, Target.newFromLocation(600, 0)),
|
new Maneuver(ship, weapon.action, Target.newFromLocation(600, 0)),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let enemy3 = battle.fleets[1].addShip();
|
let enemy3 = battle.fleets[1].addShip();
|
||||||
|
@ -68,8 +77,8 @@ module TS.SpaceTac.Specs {
|
||||||
|
|
||||||
result = imaterialize(TacticalAIHelpers.produceBlastShots(ship, battle));
|
result = imaterialize(TacticalAIHelpers.produceBlastShots(ship, battle));
|
||||||
expect(result).toEqual([
|
expect(result).toEqual([
|
||||||
new Maneuver(ship, weapon, Target.newFromLocation(600, 0)),
|
new Maneuver(ship, weapon.action, Target.newFromLocation(600, 0)),
|
||||||
new Maneuver(ship, weapon, Target.newFromLocation(600, 0)),
|
new Maneuver(ship, weapon.action, Target.newFromLocation(600, 0)),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -79,19 +88,19 @@ module TS.SpaceTac.Specs {
|
||||||
let weapon = TestTools.addWeapon(ship, 50, 5, 100);
|
let weapon = TestTools.addWeapon(ship, 50, 5, 100);
|
||||||
let engine = TestTools.addEngine(ship, 25);
|
let engine = TestTools.addEngine(ship, 25);
|
||||||
|
|
||||||
let maneuver = new Maneuver(ship, weapon, Target.newFromLocation(100, 0));
|
let maneuver = new Maneuver(ship, weapon.action, Target.newFromLocation(100, 0));
|
||||||
expect(TacticalAIHelpers.evaluateTurnCost(ship, battle, maneuver)).toBe(-Infinity);
|
expect(TacticalAIHelpers.evaluateTurnCost(ship, battle, maneuver)).toBe(-Infinity);
|
||||||
|
|
||||||
TestTools.setShipAP(ship, 10);
|
TestTools.setShipAP(ship, 10);
|
||||||
expect(TacticalAIHelpers.evaluateTurnCost(ship, battle, maneuver)).toBe(0.5); // 5 power remaining on 10
|
expect(TacticalAIHelpers.evaluateTurnCost(ship, battle, maneuver)).toBe(0.5); // 5 power remaining on 10
|
||||||
|
|
||||||
maneuver = new Maneuver(ship, weapon, Target.newFromLocation(110, 0));
|
maneuver = new Maneuver(ship, weapon.action, Target.newFromLocation(110, 0));
|
||||||
expect(TacticalAIHelpers.evaluateTurnCost(ship, battle, maneuver)).toBe(0.4); // 4 power remaining on 10
|
expect(TacticalAIHelpers.evaluateTurnCost(ship, battle, maneuver)).toBe(0.4); // 4 power remaining on 10
|
||||||
|
|
||||||
maneuver = new Maneuver(ship, weapon, Target.newFromLocation(140, 0));
|
maneuver = new Maneuver(ship, weapon.action, Target.newFromLocation(140, 0));
|
||||||
expect(TacticalAIHelpers.evaluateTurnCost(ship, battle, maneuver)).toBe(0.3); // 3 power remaining on 10
|
expect(TacticalAIHelpers.evaluateTurnCost(ship, battle, maneuver)).toBe(0.3); // 3 power remaining on 10
|
||||||
|
|
||||||
maneuver = new Maneuver(ship, weapon, Target.newFromLocation(310, 0));
|
maneuver = new Maneuver(ship, weapon.action, Target.newFromLocation(310, 0));
|
||||||
expect(TacticalAIHelpers.evaluateTurnCost(ship, battle, maneuver)).toBe(-1); // can't do in one turn
|
expect(TacticalAIHelpers.evaluateTurnCost(ship, battle, maneuver)).toBe(-1); // can't do in one turn
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -102,18 +111,18 @@ module TS.SpaceTac.Specs {
|
||||||
let engine = TestTools.addEngine(ship, 50);
|
let engine = TestTools.addEngine(ship, 50);
|
||||||
let weapon = TestTools.addWeapon(ship, 10, 2, 100, 10);
|
let weapon = TestTools.addWeapon(ship, 10, 2, 100, 10);
|
||||||
|
|
||||||
let maneuver = new Maneuver(ship, weapon, Target.newFromLocation(0, 0));
|
let maneuver = new Maneuver(ship, weapon.action, Target.newFromLocation(0, 0));
|
||||||
expect(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver)).toEqual(-0.3);
|
expect(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver)).toEqual(-0.3);
|
||||||
|
|
||||||
maneuver = new Maneuver(ship, engine, Target.newFromLocation(0, 0));
|
maneuver = new Maneuver(ship, engine.action, Target.newFromLocation(0, 0));
|
||||||
expect(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver)).toEqual(-0.5);
|
expect(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver)).toEqual(-0.5);
|
||||||
|
|
||||||
ship.setValue("power", 2);
|
ship.setValue("power", 2);
|
||||||
|
|
||||||
maneuver = new Maneuver(ship, weapon, Target.newFromLocation(0, 0));
|
maneuver = new Maneuver(ship, weapon.action, Target.newFromLocation(0, 0));
|
||||||
expect(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver)).toEqual(0.5);
|
expect(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver)).toEqual(0.5);
|
||||||
|
|
||||||
maneuver = new Maneuver(ship, engine, Target.newFromLocation(0, 0));
|
maneuver = new Maneuver(ship, engine.action, Target.newFromLocation(0, 0));
|
||||||
expect(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver)).toEqual(0);
|
expect(TacticalAIHelpers.evaluateIdling(ship, battle, maneuver)).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -130,15 +139,15 @@ module TS.SpaceTac.Specs {
|
||||||
TestTools.setShipHP(enemy2, 25, 0);
|
TestTools.setShipHP(enemy2, 25, 0);
|
||||||
|
|
||||||
// no enemies hurt
|
// no enemies hurt
|
||||||
let maneuver = new Maneuver(ship, weapon, Target.newFromLocation(100, 0));
|
let maneuver = new Maneuver(ship, weapon.action, Target.newFromLocation(100, 0));
|
||||||
expect(TacticalAIHelpers.evaluateDamageToEnemy(ship, battle, maneuver)).toEqual(0);
|
expect(TacticalAIHelpers.evaluateDamageToEnemy(ship, battle, maneuver)).toEqual(0);
|
||||||
|
|
||||||
// one enemy loses half-life
|
// one enemy loses half-life
|
||||||
maneuver = new Maneuver(ship, weapon, Target.newFromLocation(180, 0));
|
maneuver = new Maneuver(ship, weapon.action, Target.newFromLocation(180, 0));
|
||||||
expect(TacticalAIHelpers.evaluateDamageToEnemy(ship, battle, maneuver)).toEqual(0.25);
|
expect(TacticalAIHelpers.evaluateDamageToEnemy(ship, battle, maneuver)).toEqual(0.25);
|
||||||
|
|
||||||
// one enemy loses half-life, the other one is dead
|
// one enemy loses half-life, the other one is dead
|
||||||
maneuver = new Maneuver(ship, weapon, Target.newFromLocation(280, 0));
|
maneuver = new Maneuver(ship, weapon.action, Target.newFromLocation(280, 0));
|
||||||
expect(TacticalAIHelpers.evaluateDamageToEnemy(ship, battle, maneuver)).toEqual(0.625);
|
expect(TacticalAIHelpers.evaluateDamageToEnemy(ship, battle, maneuver)).toEqual(0.625);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -149,7 +158,7 @@ module TS.SpaceTac.Specs {
|
||||||
TestTools.setShipAP(ship, 10);
|
TestTools.setShipAP(ship, 10);
|
||||||
let weapon = TestTools.addWeapon(ship, 100, 1, 100, 10);
|
let weapon = TestTools.addWeapon(ship, 100, 1, 100, 10);
|
||||||
|
|
||||||
let maneuver = new Maneuver(ship, weapon, Target.newFromLocation(200, 0), 0.5);
|
let maneuver = new Maneuver(ship, weapon.action, Target.newFromLocation(200, 0), 0.5);
|
||||||
expect(maneuver.simulation.move_location).toEqual(Target.newFromLocation(100.5, 0));
|
expect(maneuver.simulation.move_location).toEqual(Target.newFromLocation(100.5, 0));
|
||||||
expect(TacticalAIHelpers.evaluateClustering(ship, battle, maneuver)).toEqual(0);
|
expect(TacticalAIHelpers.evaluateClustering(ship, battle, maneuver)).toEqual(0);
|
||||||
|
|
||||||
|
@ -172,19 +181,19 @@ module TS.SpaceTac.Specs {
|
||||||
let weapon = TestTools.addWeapon(ship, 1, 1, 400);
|
let weapon = TestTools.addWeapon(ship, 1, 1, 400);
|
||||||
|
|
||||||
ship.setArenaPosition(0, 0);
|
ship.setArenaPosition(0, 0);
|
||||||
let maneuver = new Maneuver(ship, weapon, new Target(0, 0), 0);
|
let maneuver = new Maneuver(ship, weapon.action, new Target(0, 0), 0);
|
||||||
expect(TacticalAIHelpers.evaluatePosition(ship, battle, maneuver)).toEqual(-1);
|
expect(TacticalAIHelpers.evaluatePosition(ship, battle, maneuver)).toEqual(-1);
|
||||||
|
|
||||||
ship.setArenaPosition(100, 0);
|
ship.setArenaPosition(100, 0);
|
||||||
maneuver = new Maneuver(ship, weapon, new Target(0, 0), 0);
|
maneuver = new Maneuver(ship, weapon.action, new Target(0, 0), 0);
|
||||||
expect(TacticalAIHelpers.evaluatePosition(ship, battle, maneuver)).toEqual(-1);
|
expect(TacticalAIHelpers.evaluatePosition(ship, battle, maneuver)).toEqual(-1);
|
||||||
|
|
||||||
ship.setArenaPosition(100, 10);
|
ship.setArenaPosition(100, 10);
|
||||||
maneuver = new Maneuver(ship, weapon, new Target(0, 0), 0);
|
maneuver = new Maneuver(ship, weapon.action, new Target(0, 0), 0);
|
||||||
expect(TacticalAIHelpers.evaluatePosition(ship, battle, maneuver)).toEqual(-0.6);
|
expect(TacticalAIHelpers.evaluatePosition(ship, battle, maneuver)).toEqual(-0.6);
|
||||||
|
|
||||||
ship.setArenaPosition(100, 50);
|
ship.setArenaPosition(100, 50);
|
||||||
maneuver = new Maneuver(ship, weapon, new Target(0, 0), 0);
|
maneuver = new Maneuver(ship, weapon.action, new Target(0, 0), 0);
|
||||||
expect(TacticalAIHelpers.evaluatePosition(ship, battle, maneuver)).toEqual(1);
|
expect(TacticalAIHelpers.evaluatePosition(ship, battle, maneuver)).toEqual(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,6 +10,14 @@ module TS.SpaceTac {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of all playable actions (like the actionbar for player) for a ship
|
||||||
|
*/
|
||||||
|
function getPlayableActions(ship: Ship): Iterator<BaseAction> {
|
||||||
|
let actions = ship.getAvailableActions();
|
||||||
|
return ifilter(iarray(actions), action => !action.checkCannotBeApplied(ship));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard producers and evaluators for TacticalAI
|
* Standard producers and evaluators for TacticalAI
|
||||||
*
|
*
|
||||||
|
@ -21,7 +29,7 @@ module TS.SpaceTac {
|
||||||
*/
|
*/
|
||||||
static produceDirectShots(ship: Ship, battle: Battle): TacticalProducer {
|
static produceDirectShots(ship: Ship, battle: Battle): TacticalProducer {
|
||||||
let enemies = ifilter(battle.iships(), iship => iship.alive && iship.getPlayer() !== ship.getPlayer());
|
let enemies = ifilter(battle.iships(), iship => iship.alive && iship.getPlayer() !== ship.getPlayer());
|
||||||
let weapons = ifilter(iarray(ship.listEquipment(SlotType.Weapon)), weapon => weapon.action instanceof FireWeaponAction);
|
let weapons = ifilter(getPlayableActions(ship), action => action instanceof FireWeaponAction);
|
||||||
return imap(icombine(enemies, weapons), ([enemy, weapon]) => new Maneuver(ship, weapon, Target.newFromShip(enemy)));
|
return imap(icombine(enemies, weapons), ([enemy, weapon]) => new Maneuver(ship, weapon, Target.newFromShip(enemy)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,13 +37,10 @@ module TS.SpaceTac {
|
||||||
* Produce random moves inside arena cell
|
* Produce random moves inside arena cell
|
||||||
*/
|
*/
|
||||||
static produceRandomMoves(ship: Ship, battle: Battle, cells = 10, iterations = 1, random = RandomGenerator.global): TacticalProducer {
|
static produceRandomMoves(ship: Ship, battle: Battle, cells = 10, iterations = 1, random = RandomGenerator.global): TacticalProducer {
|
||||||
let engines = ship.listEquipment(SlotType.Engine);
|
let engines = ifilter(getPlayableActions(ship), action => action instanceof MoveAction);
|
||||||
if (engines.length == 0) {
|
|
||||||
return IEMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ichainit(imap(irange(iterations), iteration => {
|
return ichainit(imap(irange(iterations), iteration => {
|
||||||
return imap(scanArena(battle, cells, random), target => new Maneuver(ship, engines[0], target))
|
let moves = icombine(engines, scanArena(battle, cells, random));
|
||||||
|
return imap(moves, ([engine, target]) => new Maneuver(ship, engine, target));
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,11 +49,11 @@ module TS.SpaceTac {
|
||||||
*/
|
*/
|
||||||
static produceBlastShots(ship: Ship, battle: Battle): TacticalProducer {
|
static produceBlastShots(ship: Ship, battle: Battle): TacticalProducer {
|
||||||
// TODO Work with groups of 3, 4 ...
|
// TODO Work with groups of 3, 4 ...
|
||||||
let weapons = ifilter(iarray(ship.listEquipment(SlotType.Weapon)), weapon => weapon.action instanceof FireWeaponAction && weapon.action.blast > 0);
|
let weapons = ifilter(getPlayableActions(ship), action => action instanceof FireWeaponAction && action.blast > 0);
|
||||||
let enemies = battle.ienemies(ship.getPlayer(), true);
|
let enemies = battle.ienemies(ship.getPlayer(), true);
|
||||||
// FIXME This produces duplicates (x, y) and (y, x)
|
// FIXME This produces duplicates (x, y) and (y, x)
|
||||||
let couples = ifilter(icombine(enemies, enemies), ([e1, e2]) => e1 != e2);
|
let couples = ifilter(icombine(enemies, enemies), ([e1, e2]) => e1 != e2);
|
||||||
let candidates = ifilter(icombine(weapons, couples), ([weapon, [e1, e2]]) => Target.newFromShip(e1).getDistanceTo(Target.newFromShip(e2)) < weapon.action.getBlastRadius(ship) * 2);
|
let candidates = ifilter(icombine(weapons, couples), ([weapon, [e1, e2]]) => Target.newFromShip(e1).getDistanceTo(Target.newFromShip(e2)) < weapon.getBlastRadius(ship) * 2);
|
||||||
let result = imap(candidates, ([weapon, [e1, e2]]) => new Maneuver(ship, weapon, Target.newFromLocation((e1.arena_x + e2.arena_x) / 2, (e1.arena_y + e2.arena_y) / 2)));
|
let result = imap(candidates, ([weapon, [e1, e2]]) => new Maneuver(ship, weapon, Target.newFromLocation((e1.arena_x + e2.arena_x) / 2, (e1.arena_y + e2.arena_y) / 2)));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -57,7 +62,7 @@ module TS.SpaceTac {
|
||||||
* Produce drone deployments.
|
* Produce drone deployments.
|
||||||
*/
|
*/
|
||||||
static produceDroneDeployments(ship: Ship, battle: Battle): TacticalProducer {
|
static produceDroneDeployments(ship: Ship, battle: Battle): TacticalProducer {
|
||||||
let drones = ifilter(iarray(ship.listEquipment(SlotType.Weapon)), weapon => weapon.action instanceof DeployDroneAction);
|
let drones = ifilter(getPlayableActions(ship), action => action instanceof DeployDroneAction);
|
||||||
let grid = scanArena(battle);
|
let grid = scanArena(battle);
|
||||||
return imap(icombine(grid, drones), ([target, drone]) => new Maneuver(ship, drone, target));
|
return imap(icombine(grid, drones), ([target, drone]) => new Maneuver(ship, drone, target));
|
||||||
}
|
}
|
||||||
|
@ -94,7 +99,7 @@ module TS.SpaceTac {
|
||||||
* Evaluate the damage done to the enemy, between -1 and 1
|
* Evaluate the damage done to the enemy, between -1 and 1
|
||||||
*/
|
*/
|
||||||
static evaluateDamageToEnemy(ship: Ship, battle: Battle, maneuver: Maneuver): number {
|
static evaluateDamageToEnemy(ship: Ship, battle: Battle, maneuver: Maneuver): number {
|
||||||
let action = maneuver.equipment.action;
|
let action = maneuver.action;
|
||||||
if (action instanceof FireWeaponAction) {
|
if (action instanceof FireWeaponAction) {
|
||||||
let enemies = imaterialize(battle.ienemies(ship.getPlayer(), true));
|
let enemies = imaterialize(battle.ienemies(ship.getPlayer(), true));
|
||||||
if (enemies.length == 0) {
|
if (enemies.length == 0) {
|
||||||
|
|
Loading…
Reference in a new issue