2017-09-24 22:23:22 +00:00
|
|
|
module TK.SpaceTac {
|
2017-02-27 00:42:12 +00:00
|
|
|
/**
|
|
|
|
* Ship maneuver for an artifical intelligence
|
|
|
|
*
|
2017-05-17 22:07:16 +00:00
|
|
|
* A maneuver is like a human player action, choosing an action and using it
|
2017-02-27 00:42:12 +00:00
|
|
|
*/
|
2015-03-12 00:00:00 +00:00
|
|
|
export class Maneuver {
|
2015-03-12 00:00:00 +00:00
|
|
|
// Concerned ship
|
2017-05-18 21:10:16 +00:00
|
|
|
ship: Ship
|
|
|
|
|
|
|
|
// Reference to battle
|
|
|
|
battle: Battle
|
2015-03-12 00:00:00 +00:00
|
|
|
|
2017-05-17 22:07:16 +00:00
|
|
|
// Action to use
|
2017-05-18 21:10:16 +00:00
|
|
|
action: BaseAction
|
2015-03-12 00:00:00 +00:00
|
|
|
|
2017-05-18 21:10:16 +00:00
|
|
|
// Target for the action
|
|
|
|
target: Target
|
2015-03-12 00:00:00 +00:00
|
|
|
|
2017-02-27 00:42:12 +00:00
|
|
|
// Result of move-fire simulation
|
2017-05-18 21:10:16 +00:00
|
|
|
simulation: MoveFireResult
|
|
|
|
|
2018-06-14 15:39:27 +00:00
|
|
|
// List of guessed effects of this maneuver (lazy property)
|
|
|
|
_effects?: BaseBattleDiff[]
|
2017-02-27 00:42:12 +00:00
|
|
|
|
2017-06-25 17:48:34 +00:00
|
|
|
constructor(ship: Ship, action: BaseAction, target: Target, move_margin = 1) {
|
2015-03-12 00:00:00 +00:00
|
|
|
this.ship = ship;
|
2017-05-18 21:10:16 +00:00
|
|
|
this.battle = nn(ship.getBattle());
|
2017-05-17 22:07:16 +00:00
|
|
|
this.action = action;
|
2015-03-12 00:00:00 +00:00
|
|
|
this.target = target;
|
2017-02-27 00:42:12 +00:00
|
|
|
|
|
|
|
let simulator = new MoveFireSimulator(this.ship);
|
2017-05-17 22:07:16 +00:00
|
|
|
this.simulation = simulator.simulateAction(this.action, this.target, move_margin);
|
2015-03-12 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
2017-05-09 23:20:05 +00:00
|
|
|
jasmineToString() {
|
2017-05-17 22:07:16 +00:00
|
|
|
return `Use ${this.action.code} on ${this.target.jasmineToString()}`;
|
2017-05-09 23:20:05 +00:00
|
|
|
}
|
|
|
|
|
2018-06-14 15:39:27 +00:00
|
|
|
get effects(): BaseBattleDiff[] {
|
|
|
|
if (!this._effects) {
|
|
|
|
let simulator = new MoveFireSimulator(this.ship);
|
|
|
|
this._effects = simulator.getExpectedDiffs(this.battle, this.simulation);
|
|
|
|
}
|
|
|
|
return this._effects;
|
|
|
|
}
|
|
|
|
|
2018-03-01 23:14:09 +00:00
|
|
|
/**
|
|
|
|
* Returns true if the maneuver has at least one part doable
|
|
|
|
*/
|
|
|
|
isPossible(): boolean {
|
|
|
|
return any(this.simulation.parts, part => part.possible);
|
|
|
|
}
|
|
|
|
|
2017-05-18 23:19:05 +00:00
|
|
|
/**
|
|
|
|
* Returns true if the maneuver cannot be fully done this turn
|
|
|
|
*/
|
|
|
|
isIncomplete(): boolean {
|
|
|
|
return (this.simulation.need_move && !this.simulation.can_end_move) || (this.simulation.need_fire && !this.simulation.can_fire);
|
|
|
|
}
|
|
|
|
|
2017-02-27 00:42:12 +00:00
|
|
|
/**
|
2017-08-23 17:59:22 +00:00
|
|
|
* Returns true if another maneuver could be done next on the same ship
|
2017-02-27 00:42:12 +00:00
|
|
|
*/
|
2017-08-23 17:59:22 +00:00
|
|
|
mayContinue(): boolean {
|
|
|
|
return this.ship.playing && !this.isIncomplete() && !(this.action instanceof EndTurnAction);
|
2015-03-12 00:00:00 +00:00
|
|
|
}
|
2017-05-09 21:09:44 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the location of the ship after the action
|
|
|
|
*/
|
|
|
|
getFinalLocation(): { x: number, y: number } {
|
|
|
|
if (this.simulation.need_move) {
|
|
|
|
return this.simulation.move_location;
|
|
|
|
} else {
|
|
|
|
return { x: this.ship.arena_x, y: this.ship.arena_y };
|
|
|
|
}
|
|
|
|
}
|
2017-05-09 23:20:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the total power usage of this maneuver
|
|
|
|
*/
|
|
|
|
getPowerUsage(): number {
|
|
|
|
return this.simulation.total_move_ap + this.simulation.total_fire_ap;
|
|
|
|
}
|
2017-05-18 21:10:16 +00:00
|
|
|
|
2017-12-21 19:04:54 +00:00
|
|
|
/**
|
|
|
|
* Standard feedback for this maneuver. It will apply it on the battle state.
|
|
|
|
*/
|
|
|
|
apply(battle: Battle): boolean {
|
|
|
|
if (!this.ship.is(battle.playing_ship)) {
|
|
|
|
console.error("Maneuver was not produced for the playing ship", this, battle);
|
|
|
|
return false;
|
|
|
|
} else if (!this.simulation.success) {
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
let parts = this.simulation.parts;
|
|
|
|
for (let i = 0; i < parts.length; i++) {
|
|
|
|
let part = parts[i];
|
|
|
|
if (part.action instanceof EndTurnAction || part.possible) {
|
2018-03-01 23:14:09 +00:00
|
|
|
if (!battle.applyOneAction(part.action.id, part.target)) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-12-21 19:04:54 +00:00
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return this.mayContinue();
|
|
|
|
}
|
|
|
|
}
|
2015-03-12 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|