1
0
Fork 0
This commit is contained in:
Michaël Lemaire 2018-07-12 16:51:30 +02:00
parent f1c8fb5289
commit 458e439bcd
9 changed files with 66 additions and 73 deletions

View File

@ -60,7 +60,6 @@ Battle
* Apply to action's default targets
* Add engine trail effect, and sound
* Find incentives to move from starting position (permanent drones or anomalies?)
* Mark targetting in error when target is refused by the action (there is already an arrow for this)
* Allow to undo last moves
* Add a battle log display
* Allow to move targetting indicator with arrow keys

View File

@ -31,11 +31,11 @@ module TK.SpaceTac.Specs {
let [ship, simulator, action] = simpleWeaponCase();
let result = simulator.simulateAction(action, new Target(ship.arena_x + 5, ship.arena_y));
check.same(result.success, true, 'success');
check.same(result.need_move, false, 'need_move');
check.same(result.need_fire, true, 'need_fire');
check.same(result.can_fire, true, 'can_fire');
check.same(result.total_fire_ap, 3, 'total_fire_ap');
check.equals(result.status, MoveFireStatus.OK, 'status');
check.equals(result.need_move, false, 'need_move');
check.equals(result.need_fire, true, 'need_fire');
check.equals(result.can_fire, true, 'can_fire');
check.equals(result.total_fire_ap, 3, 'total_fire_ap');
check.equals(result.parts, [
{ action: action, target: new Target(ship.arena_x + 5, ship.arena_y), ap: 3, possible: true }
@ -45,7 +45,7 @@ module TK.SpaceTac.Specs {
test.case("can't fire when in range, but not enough AP", check => {
let [ship, simulator, action] = simpleWeaponCase(10, 2, 3);
let result = simulator.simulateAction(action, new Target(ship.arena_x + 5, ship.arena_y));
check.equals(result.success, true, 'success');
check.equals(result.status, MoveFireStatus.NOT_ENOUGH_POWER, 'status');
check.equals(result.need_move, false, 'need_move');
check.equals(result.need_fire, true, 'need_fire');
check.equals(result.can_fire, false, 'can_fire');
@ -59,13 +59,13 @@ module TK.SpaceTac.Specs {
test.case("can't fire at invalid target", check => {
let [ship, simulator, action] = simpleWeaponCase(10, 3, 3);
let result = simulator.simulateAction(action, new Target(ship.arena_x + 5, ship.arena_y));
check.equals(result.complete, true, 'complete');
check.equals(result.status, MoveFireStatus.OK, 'status');
check.equals(result.need_fire, true, 'need_fire');
check.equals(result.can_fire, true, 'can_fire');
check.in("with invalid target", check => {
check.patch(action, "checkTarget", () => false);
result = simulator.simulateAction(action, new Target(ship.arena_x + 5, ship.arena_y));
check.equals(result.complete, false, 'complete');
check.equals(result.status, MoveFireStatus.INVALID_TARGET, 'status');
check.equals(result.need_fire, true, 'need_fire');
check.equals(result.can_fire, false, 'can_fire');
});
@ -74,7 +74,7 @@ module TK.SpaceTac.Specs {
test.case("moves straight to get within range", check => {
let [ship, simulator, action] = simpleWeaponCase();
let result = simulator.simulateAction(action, new Target(ship.arena_x + 15, ship.arena_y));
check.equals(result.success, true, 'success');
check.equals(result.status, MoveFireStatus.OK, 'status');
check.equals(result.need_move, true, 'need_move');
check.equals(result.can_move, true, 'can_move');
check.equals(result.can_end_move, true, 'can_end_move');
@ -151,7 +151,7 @@ module TK.SpaceTac.Specs {
test.case("moves to get in range, even if not enough AP to fire", check => {
let [ship, simulator, action] = simpleWeaponCase(8, 3, 2, 5);
let result = simulator.simulateAction(action, new Target(ship.arena_x + 18, ship.arena_y));
check.same(result.success, true, 'success');
check.same(result.status, MoveFireStatus.NOT_ENOUGH_POWER, 'status');
check.same(result.need_move, true, 'need_move');
check.same(result.can_end_move, true, 'can_end_move');
check.equals(result.move_location, new Target(ship.arena_x + 10, ship.arena_y));
@ -171,7 +171,7 @@ module TK.SpaceTac.Specs {
let [ship, simulator, action] = simpleWeaponCase();
let move_action = ship.actions.listAll().filter(action => action instanceof MoveAction)[0];
let result = simulator.simulateAction(move_action, new Target(ship.arena_x, ship.arena_y));
check.equals(result.success, false);
check.equals(result.status, MoveFireStatus.NO_ACTION, 'status');
check.equals(result.need_move, false);
check.equals(result.need_fire, false);
check.equals(result.parts, []);
@ -180,10 +180,10 @@ module TK.SpaceTac.Specs {
test.case("does not move if already in range, even if in the safety margin", check => {
let [ship, simulator, action] = simpleWeaponCase(100);
let result = simulator.simulateAction(action, new Target(ship.arena_x + 97, ship.arena_y), 5);
check.equals(result.success, true);
check.equals(result.status, MoveFireStatus.OK, 'status');
check.equals(result.need_move, false);
result = simulator.simulateAction(action, new Target(ship.arena_x + 101, ship.arena_y), 5);
check.equals(result.success, true);
check.equals(result.status, MoveFireStatus.OK, 'status');
check.equals(result.need_move, true);
check.equals(result.move_location, new Target(ship.arena_x + 6, ship.arena_y));
});

View File

@ -7,6 +7,17 @@ module TK.SpaceTac {
NO_VECTOR_FOUND,
}
/**
* Status for simulation
*/
export enum MoveFireStatus {
OK,
NO_ACTION,
NOT_ENOUGH_POWER,
INVALID_TARGET,
IMPOSSIBLE_APPROACH,
}
/**
* A single action in the sequence result from the simulator
*/
@ -21,12 +32,10 @@ module TK.SpaceTac {
* A simulation result
*/
export class MoveFireResult {
// Simulation success, false only if no route can be found
success = false
// Simulation status
status = MoveFireStatus.OK
// Ideal successive parts to make the full move+fire
parts: MoveFirePart[] = []
// Simulation complete (both move and fire are possible)
complete = false
need_move = false
can_move = false
@ -135,7 +144,7 @@ module TK.SpaceTac {
} else if (approach != ApproachSimulationError.NO_MOVE_NEEDED) {
result.need_move = true;
result.can_move = false;
result.success = false;
result.status = MoveFireStatus.IMPOSSIBLE_APPROACH;
return result;
}
}
@ -145,6 +154,9 @@ module TK.SpaceTac {
result.need_move = false;
} else {
result.can_move = bool(move_action.checkTarget(this.ship, move_target));
if (!result.can_move) {
result.status = MoveFireStatus.INVALID_TARGET;
}
}
}
@ -157,22 +169,33 @@ module TK.SpaceTac {
// TODO Split in "this turn" part and "next turn" part if needed
result.parts.push({ action: move_action, target: move_target, ap: result.total_move_ap, possible: result.can_move });
if (!result.can_end_move) {
result.status = MoveFireStatus.NOT_ENOUGH_POWER;
}
ap -= result.total_move_ap;
}
// Check action AP
if (action instanceof MoveAction) {
result.success = result.need_move && result.can_move;
} else {
if (!(action instanceof MoveAction)) {
result.need_fire = true;
result.total_fire_ap = action.getPowerUsage(this.ship, target);
result.can_fire = (action.checkTarget(this.ship, target, result.move_location)) && (result.total_fire_ap <= ap);
if (action.checkTarget(this.ship, target, result.move_location)) {
if (result.total_fire_ap <= ap) {
result.can_fire = true;
} else {
result.status = MoveFireStatus.NOT_ENOUGH_POWER;
}
} else {
result.status = MoveFireStatus.INVALID_TARGET;
}
result.fire_location = target;
result.parts.push({ action: action, target: target, ap: result.total_fire_ap, possible: (!result.need_move || result.can_end_move) && result.can_fire });
result.success = true;
}
result.complete = (!result.need_move || result.can_end_move) && (!result.need_fire || result.can_fire);
if (!result.need_move && !result.need_fire) {
result.status = MoveFireStatus.NO_ACTION;
}
return result;
}

View File

@ -237,14 +237,10 @@ module TK.SpaceTac {
* Will call checkLocationTarget or checkShipTarget by default
*/
checkTarget(ship: Ship, target: Target, from: IArenaLocation = ship.location): boolean {
if (this.checkCannotBeApplied(ship)) {
return false;
if (target.isShip()) {
return this.checkShipTarget(ship, target, from);
} else {
if (target.isShip()) {
return this.checkShipTarget(ship, target, from);
} else {
return this.checkLocationTarget(ship, target, from);
}
return this.checkLocationTarget(ship, target, from);
}
}

View File

@ -91,7 +91,7 @@ module TK.SpaceTac {
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) {
} else if (this.simulation.status != MoveFireStatus.OK) {
return false;
} else {
let parts = this.simulation.parts;

View File

@ -7,7 +7,8 @@ module TK.SpaceTac.Specs {
constructor(score: number) {
let battle = new Battle();
let ship = battle.fleets[0].addShip();
super(ship, new BaseAction("nothing"), new Target(0, 0));
let action = ship.actions.addCustom(new TriggerAction("nothing", { power: 0 }));
super(ship, action, Target.newFromShip(ship));
this.score = score;
}
}

View File

@ -212,7 +212,7 @@ module TK.SpaceTac.UI {
* Temporarily set power status for a given move-fire simulation
*/
updateFromSimulation(action: BaseAction, simulation: MoveFireResult) {
if (simulation.complete) {
if (simulation.status == MoveFireStatus.OK) {
this.updateSelectedActionPower(simulation.total_move_ap, simulation.total_fire_ap, action);
} else {
this.updateSelectedActionPower(0, 0, action);

View File

@ -89,8 +89,7 @@ module TK.SpaceTac.UI.Specs {
check.patch(targetting, "simulate", () => {
let result = new MoveFireResult();
result.success = true;
result.complete = true;
result.status = MoveFireStatus.OK;
result.need_move = true;
result.move_location = Target.newFromLocation(80, 20);
result.can_move = true;

View File

@ -236,10 +236,17 @@ module TK.SpaceTac.UI {
let from = (simulation.need_fire && this.mode != ActionTargettingMode.SURROUNDINGS) ? simulation.move_location : this.ship.location;
let angle = Math.atan2(this.target.y - from.y, this.target.x - from.x);
if (simulation.success) {
if (simulation.status == MoveFireStatus.IMPOSSIBLE_APPROACH || simulation.status == MoveFireStatus.INVALID_TARGET || simulation.status == MoveFireStatus.NO_ACTION) {
this.drawVector(0x888888, this.ship.arena_x, this.ship.arena_y, this.target.x, this.target.y);
this.fire_arrow.setPosition(this.target.x, this.target.y);
this.fire_arrow.setRotation(angle);
this.view.changeImage(this.fire_arrow, (simulation.status == MoveFireStatus.INVALID_TARGET) ? "battle-hud-simulator-target" : "battle-hud-simulator-failed");
this.fire_arrow.visible = true;
this.impact_area.visible = false;
} else {
let previous: MoveFirePart | null = null;
simulation.parts.forEach(part => {
this.drawPart(part, simulation.complete, previous);
this.drawPart(part, simulation.status == MoveFireStatus.OK, previous);
previous = part;
});
@ -266,7 +273,7 @@ module TK.SpaceTac.UI {
if (this.mode != ActionTargettingMode.SURROUNDINGS) {
this.fire_arrow.setPosition(this.target.x, this.target.y);
this.fire_arrow.setRotation(angle);
this.view.changeImage(this.fire_arrow, simulation.complete ? "battle-hud-simulator-ok" : "battle-hud-simulator-power");
this.view.changeImage(this.fire_arrow, (simulation.status == MoveFireStatus.OK) ? "battle-hud-simulator-ok" : "battle-hud-simulator-power");
this.fire_arrow.visible = true;
}
} else {
@ -274,13 +281,6 @@ module TK.SpaceTac.UI {
this.impact_indicators.visible = false;
this.fire_arrow.visible = false;
}
} else {
this.drawVector(0x888888, this.ship.arena_x, this.ship.arena_y, this.target.x, this.target.y);
this.fire_arrow.setPosition(this.target.x, this.target.y);
this.fire_arrow.setRotation(angle);
this.view.changeImage(this.fire_arrow, "battle-hud-simulator-failed");
this.fire_arrow.visible = true;
this.impact_area.visible = false;
}
this.updateDiffsDisplay();
@ -292,30 +292,6 @@ module TK.SpaceTac.UI {
// Toggle tactical mode
this.tactical_mode(bool(this.action));
// Toggle range hint
if (this.ship && this.action) {
if (this.simulation.need_move) {
let move_action: MoveAction | null = null;
if (this.simulation.success) {
let last_move = first(acopy(this.simulation.parts).reverse(), part => part.action instanceof MoveAction);
if (last_move) {
move_action = <MoveAction>last_move.action;
}
} else {
let engine = new MoveFireSimulator(this.ship, new ArenaGrid()).findEngine();
if (engine) {
move_action = engine;
}
}
if (move_action) {
let power = this.ship.getValue("power");
if (this.action !== move_action) {
power = Math.max(power - this.action.getPowerUsage(this.ship, this.target), 0);
}
}
}
}
}
/**
@ -406,8 +382,7 @@ module TK.SpaceTac.UI {
if (this.active) {
this.simulate();
if (this.ship && this.simulation.complete) {
let ship = this.ship;
if (this.simulation.status == MoveFireStatus.OK) {
this.simulation.parts.forEach(part => {
if (part.possible) {
applier(part.action, part.target);