1
0
Fork 0

Display simulated ship displacement effects while targetting

This commit is contained in:
Michaël Lemaire 2018-06-13 23:52:36 +02:00
parent 7d586d5a2b
commit 4e624dc9db
14 changed files with 108 additions and 29 deletions

View file

@ -43,7 +43,7 @@ Battle
* Improve arena ships layering (sometimes information is displayed behind other sprites) * Improve arena ships layering (sometimes information is displayed behind other sprites)
* In the ship tooltip, show power cost, toggled and overheat states * In the ship tooltip, show power cost, toggled and overheat states
* Display shield (and its (dis)appearance) * Display shield (and its (dis)appearance)
* Display estimated damage and displacement in targetting mode * Display estimated damage in targetting mode
* Add a voluntary retreat option * Add a voluntary retreat option
* Toggle bar/text display in power section of action bar * Toggle bar/text display in power section of action bar
* Show a cooldown indicator on move action icon, if the simulation would cause the engine to overheat * Show a cooldown indicator on move action icon, if the simulation would cause the engine to overheat

View file

@ -148,7 +148,7 @@ module TK.SpaceTac {
let diff = battle.log.get(battle.log.count() - 1); let diff = battle.log.get(battle.log.count() - 1);
if (diff instanceof EndBattleDiff) { if (diff instanceof EndBattleDiff) {
check.notequals(diff.outcome.winner, null); check.notequals(diff.outcome.winner, null);
check.same(diff.outcome.winner, fleet2); check.same(diff.outcome.winner, fleet2.id);
} else { } else {
check.fail("Not an EndBattleDiff"); check.fail("Not an EndBattleDiff");
} }

View file

@ -349,10 +349,12 @@ module TK.SpaceTac {
/** /**
* Perform all battle checks to ensure the state is consistent * Perform all battle checks to ensure the state is consistent
*
* Returns all applied diffs
*/ */
performChecks(): void { performChecks(): BaseBattleDiff[] {
let checks = new BattleChecks(this); let checks = new BattleChecks(this);
checks.apply(); return checks.apply();
} }
/** /**

View file

@ -7,7 +7,7 @@ module TK.SpaceTac.Specs {
cheats.win(); cheats.win();
check.equals(battle.ended, true, "ended"); check.equals(battle.ended, true, "ended");
check.same(nn(battle.outcome).winner, battle.fleets[0], "winner"); check.same(nn(battle.outcome).winner, battle.fleets[0].id, "winner");
check.equals(any(battle.fleets[1].ships, ship => ship.alive), false, "all enemies dead"); check.equals(any(battle.fleets[1].ships, ship => ship.alive), false, "all enemies dead");
}) })
@ -18,7 +18,7 @@ module TK.SpaceTac.Specs {
cheats.lose(); cheats.lose();
check.equals(battle.ended, true, "ended"); check.equals(battle.ended, true, "ended");
check.same(nn(battle.outcome).winner, battle.fleets[1], "winner"); check.same(nn(battle.outcome).winner, battle.fleets[1].id, "winner");
check.equals(any(battle.fleets[0].ships, ship => ship.alive), false, "all allies dead"); check.equals(any(battle.fleets[0].ships, ship => ship.alive), false, "all allies dead");
}) })
}) })

View file

@ -13,7 +13,8 @@ module TK.SpaceTac {
/** /**
* Apply all the checks * Apply all the checks
*/ */
apply(): void { apply(): BaseBattleDiff[] {
let all: BaseBattleDiff[] = [];
let diffs: BaseBattleDiff[]; let diffs: BaseBattleDiff[];
let loops = 0; let loops = 0;
@ -23,6 +24,7 @@ module TK.SpaceTac {
if (diffs.length > 0) { if (diffs.length > 0) {
//console.log("Battle checks diffs", diffs); //console.log("Battle checks diffs", diffs);
this.battle.applyDiffs(diffs); this.battle.applyDiffs(diffs);
all = all.concat(diffs);
} }
loops += 1; loops += 1;
@ -31,6 +33,8 @@ module TK.SpaceTac {
break; break;
} }
} while (diffs.length > 0); } while (diffs.length > 0);
return all;
} }
/** /**

View file

@ -9,10 +9,10 @@ module TK.SpaceTac {
draw: boolean draw: boolean
// Victorious fleet // Victorious fleet
winner: Fleet | null winner: RObjectId | null
constructor(winner: Fleet | null) { constructor(winner: Fleet | null) {
this.winner = winner; this.winner = winner ? winner.id : null;
this.draw = winner ? false : true; this.draw = winner ? false : true;
} }
@ -21,7 +21,7 @@ module TK.SpaceTac {
*/ */
grantExperience(fleets: Fleet[]) { grantExperience(fleets: Fleet[]) {
fleets.forEach(fleet => { fleets.forEach(fleet => {
let winfactor = (fleet == this.winner) ? 0.03 : (this.draw ? 0.01 : 0.005); let winfactor = (fleet.is(this.winner)) ? 0.03 : (this.draw ? 0.01 : 0.005);
let enemies = flatten(fleets.filter(f => f !== fleet).map(f => f.ships)); let enemies = flatten(fleets.filter(f => f !== fleet).map(f => f.ships));
let difficulty = sum(enemies.map(enemy => 100 + enemy.level.getExperience())); let difficulty = sum(enemies.map(enemy => 100 + enemy.level.getExperience()));
fleet.ships.forEach(ship => { fleet.ships.forEach(ship => {

View file

@ -2,7 +2,7 @@ module TK.SpaceTac {
/** /**
* A fleet of ships, all belonging to the same player * A fleet of ships, all belonging to the same player
*/ */
export class Fleet { export class Fleet extends RObject {
// Fleet owner // Fleet owner
player: Player player: Player
@ -26,6 +26,8 @@ module TK.SpaceTac {
// Create a fleet, bound to a player // Create a fleet, bound to a player
constructor(player = new Player()) { constructor(player = new Player()) {
super();
this.player = player; this.player = player;
this.name = player ? player.name : "Fleet"; this.name = player ? player.name : "Fleet";
this.ships = []; this.ships = [];

View file

@ -172,5 +172,36 @@ module TK.SpaceTac.Specs {
check.equals(result.need_move, true); check.equals(result.need_move, true);
check.equals(result.move_location, new Target(ship.arena_x + 6, ship.arena_y)); check.equals(result.move_location, new Target(ship.arena_x + 6, ship.arena_y));
}); });
test.case("simulates the results on a fake battle, to provide a list of expected diffs", check => {
let battle = TestTools.createBattle();
let ship = battle.fleets[0].ships[0];
let enemy = battle.fleets[1].ships[0];
ship.setArenaPosition(100, 100);
enemy.setArenaPosition(300, 100);
TestTools.setShipModel(ship, 1, 1, 3);
TestTools.setShipModel(enemy, 2, 1);
let engine = TestTools.addEngine(ship, 80);
let weapon = TestTools.addWeapon(ship, 5, 1, 150);
let simulator = new MoveFireSimulator(ship);
let result = simulator.simulateAction(weapon, Target.newFromShip(enemy), 5);
let diffs = simulator.getExpectedDiffs(nn(ship.getBattle()), result);
check.equals(diffs, [
new ShipActionUsedDiff(ship, engine, Target.newFromLocation(155, 100)),
new ShipValueDiff(ship, "power", -1),
new ShipMoveDiff(ship, ship.location, new ArenaLocationAngle(155, 100), engine),
new ShipActionUsedDiff(ship, weapon, Target.newFromShip(enemy)),
new ShipValueDiff(ship, "power", -1),
new ProjectileFiredDiff(ship, weapon, Target.newFromShip(enemy)),
new ShipDamageDiff(enemy, 2, 1, 0, 5),
new ShipValueDiff(enemy, "shield", -1),
new ShipValueDiff(enemy, "hull", -2),
new ShipDeathDiff(battle, enemy),
new EndBattleDiff(battle.fleets[0], 0)
]);
check.equals(enemy.getValue("hull"), 2);
check.equals(enemy.getValue("hull"), 2);
});
}); });
} }

View file

@ -187,5 +187,25 @@ module TK.SpaceTac {
return result; return result;
} }
/**
* Apply a move-fire simulation result, and predict the diffs it will apply on a battle
*
* The original battle passed as parameter will be duplicated, and not altered
*/
getExpectedDiffs(battle: Battle, simulation: MoveFireResult): BaseBattleDiff[] {
let sim_battle = duplicate(battle, TK.SpaceTac);
let sim_ship = nn(sim_battle.getShip(this.ship.id));
let results: BaseBattleDiff[] = [];
simulation.parts.forEach(part => {
let diffs = part.action.getDiffs(sim_ship, battle, part.target);
results = results.concat(diffs);
sim_battle.applyDiffs(diffs);
diffs = sim_battle.performChecks();
results = results.concat(diffs);
});
return results;
}
} }
} }

View file

@ -173,7 +173,7 @@ module TK.SpaceTac {
* Resolves the encounter from a battle outcome * Resolves the encounter from a battle outcome
*/ */
resolveEncounter(outcome: BattleOutcome) { resolveEncounter(outcome: BattleOutcome) {
if (this.encounter && outcome.winner && outcome.winner != this.encounter) { if (this.encounter && outcome.winner && !this.encounter.is(outcome.winner)) {
this.clearEncounter(); this.clearEncounter();
} }
} }

View file

@ -17,7 +17,7 @@ module TK.SpaceTac.Specs {
}, },
check => { check => {
check.equals(battle.ended, true, "battle is ended"); check.equals(battle.ended, true, "battle is ended");
check.same(nn(battle.outcome).winner, battle.fleets[1], "battle has an outcome"); check.same(nn(battle.outcome).winner, battle.fleets[1].id, "battle has an outcome");
}, },
]); ]);
}); });

View file

@ -62,7 +62,7 @@ module TK.SpaceTac.Specs {
ship.setDead(); ship.setDead();
battle.performChecks(); battle.performChecks();
check.equals(battle.ended, true); check.equals(battle.ended, true);
check.notsame(nn(battle.outcome).winner, fleet); check.notsame(nn(battle.outcome).winner, fleet.id);
}) })
}) })
} }

View file

@ -38,7 +38,7 @@ module TK.SpaceTac.UI {
refreshContent(): void { refreshContent(): void {
let parent = this.battleview; let parent = this.battleview;
let outcome = this.outcome; let outcome = this.outcome;
let victory = outcome.winner && this.player.is(outcome.winner.player); let victory = outcome.winner && this.player.fleet.is(outcome.winner);
this.content.clear(); this.content.clear();

View file

@ -16,7 +16,7 @@ module TK.SpaceTac.UI {
// Simulated result // Simulated result
simulation = new MoveFireResult() simulation = new MoveFireResult()
effects: BaseBattleDiff[] = [] simulated_diffs: BaseBattleDiff[] = []
// Move and fire lines // Move and fire lines
drawn_info: UIGraphics drawn_info: UIGraphics
@ -27,6 +27,9 @@ module TK.SpaceTac.UI {
impact_area: UIGraphics impact_area: UIGraphics
impact_indicators: UIContainer impact_indicators: UIContainer
// Diffs display
diffs_move: UIGraphics
// Collaborators to update // Collaborators to update
actionbar: ActionBar actionbar: ActionBar
range_hint: RangeHint range_hint: RangeHint
@ -46,18 +49,16 @@ module TK.SpaceTac.UI {
builder = builder.in(this.container); builder = builder.in(this.container);
// Visual effects // Visual effects
this.impact_area = builder.graphics("impact-area"); this.impact_area = builder.graphics("impact-area", 0, 0, false);
this.impact_area.setVisible(false); this.diffs_move = builder.graphics("effects-move");
this.drawn_info = builder.graphics("lines"); this.drawn_info = builder.graphics("lines", 0, 0, false);
this.drawn_info.setVisible(false);
this.move_ghost = builder.image("common-transparent", 0, 0, true); this.move_ghost = builder.image("common-transparent", 0, 0, true);
this.move_ghost.setAlpha(0.8); this.move_ghost.setAlpha(0.8);
this.move_ghost.setVisible(false); this.move_ghost.setVisible(false);
this.fire_arrow = builder.image("battle-hud-simulator-ok"); this.fire_arrow = builder.image("battle-hud-simulator-ok");
this.fire_arrow.setOrigin(1, 0.5); this.fire_arrow.setOrigin(1, 0.5);
this.fire_arrow.setVisible(false); this.fire_arrow.setVisible(false);
this.impact_indicators = builder.container("impact-indicators"); this.impact_indicators = builder.container("impact-indicators", 0, 0, false);
this.impact_indicators.setVisible(false);
} }
/** /**
@ -200,6 +201,25 @@ module TK.SpaceTac.UI {
} }
} }
/**
* Update information about simulated diffs
*/
updateDiffsDisplay(): void {
this.diffs_move.clear();
this.simulated_diffs.forEach(diff => {
if (diff instanceof ShipMoveDiff) {
this.diffs_move.addLine({
start: diff.start,
end: diff.end,
width: 4,
color: 0xFFFFFF,
alpha: 0.5
});
}
});
}
/** /**
* Update visual effects to show the simulation of current action/target * Update visual effects to show the simulation of current action/target
*/ */
@ -259,6 +279,9 @@ module TK.SpaceTac.UI {
this.fire_arrow.visible = true; this.fire_arrow.visible = true;
this.impact_area.visible = false; this.impact_area.visible = false;
} }
this.updateDiffsDisplay();
this.container.visible = true; this.container.visible = true;
} else { } else {
this.container.visible = false; this.container.visible = false;
@ -305,16 +328,13 @@ module TK.SpaceTac.UI {
*/ */
simulate(): void { simulate(): void {
if (this.ship && this.action && this.target) { if (this.ship && this.action && this.target) {
let ship = this.ship; let battle = nn(this.ship.getBattle());
let simulator = new MoveFireSimulator(ship); let simulator = new MoveFireSimulator(this.ship);
this.simulation = simulator.simulateAction(this.action, this.target, 1); this.simulation = simulator.simulateAction(this.action, this.target, 1);
this.simulated_diffs = simulator.getExpectedDiffs(battle, this.simulation);
this.effects = flatten(this.simulation.parts.map(part =>
part.action.getDiffs(ship, nn(ship.getBattle()), part.target)
));
} else { } else {
this.simulation = new MoveFireResult(); this.simulation = new MoveFireResult();
this.effects = []; this.simulated_diffs = [];
} }
} }