2017-02-09 00:00:35 +00:00
|
|
|
module TS.SpaceTac {
|
2017-02-05 18:01:00 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A single action in the sequence result from the simulator
|
|
|
|
*/
|
2017-02-27 00:42:12 +00:00
|
|
|
export type MoveFirePart = {
|
2017-02-05 18:01:00 +00:00
|
|
|
action: BaseAction
|
|
|
|
target: Target
|
|
|
|
ap: number
|
2017-03-07 22:16:47 +00:00
|
|
|
possible: boolean
|
2017-02-05 18:01:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A simulation result
|
|
|
|
*/
|
2017-02-27 00:42:12 +00:00
|
|
|
export class MoveFireResult {
|
2017-02-05 18:01:00 +00:00
|
|
|
// Simulation success, false only if no route can be found
|
|
|
|
success = false
|
|
|
|
// Ideal successive parts to make the full move+fire
|
|
|
|
parts: MoveFirePart[] = []
|
|
|
|
|
|
|
|
need_move = false
|
|
|
|
can_move = false
|
|
|
|
can_end_move = false
|
|
|
|
total_move_ap = 0
|
|
|
|
move_location = new Target(0, 0, null)
|
|
|
|
|
|
|
|
need_fire = false
|
|
|
|
can_fire = false
|
|
|
|
total_fire_ap = 0
|
|
|
|
fire_location = new Target(0, 0, null)
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Utility to simulate a move+fire action.
|
|
|
|
*
|
|
|
|
* This is also a helper to bring a ship in range to fire a weapon.
|
|
|
|
*/
|
|
|
|
export class MoveFireSimulator {
|
|
|
|
ship: Ship;
|
|
|
|
|
|
|
|
constructor(ship: Ship) {
|
|
|
|
this.ship = ship;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find the best available engine for moving
|
|
|
|
*/
|
|
|
|
findBestEngine(): Equipment | null {
|
|
|
|
let engines = this.ship.listEquipment(SlotType.Engine);
|
|
|
|
if (engines.length == 0) {
|
|
|
|
return null;
|
|
|
|
} else {
|
2017-04-18 19:51:23 +00:00
|
|
|
engines.sort((a, b) => (a.action instanceof MoveAction && b.action instanceof MoveAction) ? cmp(b.action.distance_per_power, a.action.distance_per_power) : 0);
|
2017-02-05 18:01:00 +00:00
|
|
|
return engines[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Simulate a given action on a given valid target.
|
|
|
|
*/
|
2017-03-07 22:16:47 +00:00
|
|
|
simulateAction(action: BaseAction, target: Target, move_margin = 0): MoveFireResult {
|
2017-03-07 19:27:46 +00:00
|
|
|
let result = new MoveFireResult();
|
|
|
|
|
2017-02-05 18:01:00 +00:00
|
|
|
let dx = target.x - this.ship.arena_x;
|
|
|
|
let dy = target.y - this.ship.arena_y;
|
|
|
|
let distance = Math.sqrt(dx * dx + dy * dy);
|
2017-03-07 19:27:46 +00:00
|
|
|
|
2017-02-07 19:15:21 +00:00
|
|
|
let ap = this.ship.values.power.get();
|
2017-02-27 00:42:12 +00:00
|
|
|
let action_radius = action.getRangeRadius(this.ship);
|
2017-02-05 18:01:00 +00:00
|
|
|
|
2017-02-27 00:42:12 +00:00
|
|
|
if (action instanceof MoveAction || distance > action_radius) {
|
2017-03-07 22:16:47 +00:00
|
|
|
let move_distance = action instanceof MoveAction ? distance : (distance - action_radius + move_margin);
|
2017-03-07 19:27:46 +00:00
|
|
|
if (move_distance > 0.000001) {
|
|
|
|
result.need_move = true;
|
|
|
|
|
|
|
|
let move_target = new Target(this.ship.arena_x + dx * move_distance / distance, this.ship.arena_y + dy * move_distance / distance, null);
|
|
|
|
let engine = this.findBestEngine();
|
|
|
|
if (engine) {
|
|
|
|
result.total_move_ap = engine.action.getActionPointsUsage(this.ship, move_target);
|
|
|
|
result.can_move = ap > 0;
|
|
|
|
result.can_end_move = result.total_move_ap <= ap;
|
|
|
|
result.move_location = move_target;
|
2017-03-07 22:16:47 +00:00
|
|
|
// TODO Split in "this turn" part and "next turn" part if needed
|
|
|
|
result.parts.push({ action: engine.action, target: move_target, ap: result.total_move_ap, possible: result.can_move });
|
2017-02-05 18:01:00 +00:00
|
|
|
|
2017-03-07 19:27:46 +00:00
|
|
|
ap -= result.total_move_ap;
|
|
|
|
distance -= move_distance;
|
|
|
|
}
|
2017-02-05 18:01:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-27 00:42:12 +00:00
|
|
|
if (distance <= action_radius) {
|
2017-02-05 18:01:00 +00:00
|
|
|
result.success = true;
|
|
|
|
if (!(action instanceof MoveAction)) {
|
|
|
|
result.need_fire = true;
|
2017-03-07 19:27:46 +00:00
|
|
|
result.total_fire_ap = action.getActionPointsUsage(this.ship, target);
|
2017-02-05 18:01:00 +00:00
|
|
|
result.can_fire = result.total_fire_ap <= ap;
|
|
|
|
result.fire_location = target;
|
2017-03-08 23:18:40 +00:00
|
|
|
result.parts.push({ action: action, target: target, ap: result.total_fire_ap, possible: (!result.need_move || result.can_end_move) && result.can_fire });
|
2017-02-05 18:01:00 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
result.success = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|