diff --git a/src/core/Battle.ts b/src/core/Battle.ts
index f86dc09..04a916b 100644
--- a/src/core/Battle.ts
+++ b/src/core/Battle.ts
@@ -61,6 +61,14 @@ module TK.SpaceTac {
return bool(this.outcome);
}
+ /**
+ * Apply a turn plan through a resolution
+ */
+ applyTurnPlan(plan: TurnPlan): void {
+ const resolution = new TurnResolution(this, plan);
+ resolution.resolve();
+ }
+
/**
* Apply a list of diffs to the game state, and add them to the log.
*
diff --git a/src/core/Ship.ts b/src/core/Ship.ts
index f2b1687..1de7755 100644
--- a/src/core/Ship.ts
+++ b/src/core/Ship.ts
@@ -111,8 +111,9 @@ module TK.SpaceTac {
}
// Make an initiative throw, to resolve play order in a battle
- throwInitiative(gen: RandomGenerator): void {
+ throwInitiative(gen: RandomGenerator): number {
this.play_priority = gen.random() * this.attributes.initiative.get();
+ return this.play_priority;
}
/**
diff --git a/src/core/TurnResolution.spec.ts b/src/core/TurnResolution.spec.ts
new file mode 100644
index 0000000..7e9ea60
--- /dev/null
+++ b/src/core/TurnResolution.spec.ts
@@ -0,0 +1,53 @@
+module TK.SpaceTac {
+ testing("TurnResolution", test => {
+ test.case("defines play order by initiative throws", check => {
+ const fleet1 = new Fleet();
+ const fleet2 = new Fleet();
+
+ const ship1 = new Ship(fleet1, "F1S1");
+ TestTools.setAttribute(ship1, "initiative", 2);
+ const ship2 = new Ship(fleet1, "F1S2");
+ TestTools.setAttribute(ship2, "initiative", 4);
+ const ship3 = new Ship(fleet1, "F1S3");
+ TestTools.setAttribute(ship3, "initiative", 1);
+ const ship4 = new Ship(fleet2, "F2S1");
+ TestTools.setAttribute(ship4, "initiative", 8);
+ const ship5 = new Ship(fleet2, "F2S2");
+ TestTools.setAttribute(ship5, "initiative", 2);
+
+ const battle = new Battle(fleet1, fleet2);
+ const random = new SkewedRandomGenerator([1.0, 0.1, 1.0, 0.2, 0.6]);
+ const resolution = new TurnResolution(battle, { fleets: [] }, random);
+
+ check.equals(resolution.play_order, []);
+ resolution.throwInitiative();
+ check.equals(resolution.play_order, [ship1, ship4, ship5, ship3, ship2]);
+ });
+
+ test.case("logs a turn start diff", check => {
+ const battle = new Battle();
+ const resolution = new TurnResolution(battle, { fleets: [] });
+ const ships = [new Ship(), new Ship()]
+ resolution.play_order = ships;
+
+ check.equals(battle.log.count(), 0);
+ resolution.logStart();
+ check.equals(battle.log.count(), 1);
+ const diff = battle.log.get(0);
+ if (check.instance(diff, TurnStartDiff, "diff should be a TurnStartDiff")) {
+ check.equals(diff.play_order, [ships[0].id, ships[1].id]);
+ }
+ });
+
+ test.case("logs a turn end diff", check => {
+ const battle = new Battle();
+ const resolution = new TurnResolution(battle, { fleets: [] });
+
+ check.equals(battle.log.count(), 0);
+ resolution.logEnd();
+ check.equals(battle.log.count(), 1);
+ const diff = battle.log.get(0);
+ check.instance(diff, TurnEndDiff, "diff should be a TurnEndDiff");
+ });
+ });
+}
diff --git a/src/core/TurnResolution.ts b/src/core/TurnResolution.ts
new file mode 100644
index 0000000..df32a9f
--- /dev/null
+++ b/src/core/TurnResolution.ts
@@ -0,0 +1,70 @@
+namespace TK.SpaceTac {
+ /**
+ * The machinery to apply a turn plan, in order to resolve the current turn
+ */
+ export class TurnResolution {
+ play_order: Ship[] = []
+
+ constructor(readonly battle: Battle, readonly plan: TurnPlan, readonly random = new RandomGenerator()) {
+ }
+
+ /**
+ * Perform the whole resolution
+ */
+ resolve(): void {
+ this.throwInitiative();
+ this.logStart();
+ this.performActions(ActionCategory.PASSIVE);
+ this.performActions(ActionCategory.MOVE);
+ this.performActions(ActionCategory.ACTIVE);
+ this.logEnd();
+ }
+
+ /**
+ * Perform an initiative throw, to obtain an order in which the ships will play
+ */
+ throwInitiative(): void {
+ const with_thrown = this.battle.ships.list().map(ship => [ship, ship.throwInitiative(this.random)] as [Ship, number]);
+ const sorted_by_thrown = sortedBy(with_thrown, ([_, thrown]) => thrown);
+ this.play_order = sorted_by_thrown.reverse().map(([ship, _]) => ship);
+ }
+
+ /**
+ * Log a turn start diff
+ */
+ logStart(): void {
+ this.battle.applyDiffs([new TurnStartDiff(this.play_order)]);
+ }
+
+ /**
+ * Perform all actions of a given category, for all ships in the initiative order
+ */
+ performActions(category: ActionCategory): void {
+ this.play_order.forEach(ship => this.performActionsForShip(ship, category));
+ }
+
+ /**
+ * Perform all actions of a given category, for one given ship
+ */
+ performActionsForShip(ship: Ship, category: ActionCategory): void {
+ this.plan.fleets.forEach(fleetplan => {
+ fleetplan.ships.forEach(shipplan => {
+ if (ship.is(shipplan.ship)) {
+ shipplan.actions.forEach(actionplan => {
+ if (actionplan.category === category) {
+ this.battle.applyOneAction(actionplan.action, actionplan.target);
+ }
+ });
+ }
+ });
+ });
+ }
+
+ /**
+ * Log a turn end diff
+ */
+ logEnd(): void {
+ this.battle.applyDiffs([new TurnEndDiff()]);
+ }
+ }
+}
diff --git a/src/core/diffs/TurnEndDiff.ts b/src/core/diffs/TurnEndDiff.ts
new file mode 100644
index 0000000..b88333f
--- /dev/null
+++ b/src/core/diffs/TurnEndDiff.ts
@@ -0,0 +1,9 @@
+///
+
+module TK.SpaceTac {
+ /**
+ * A turn has ended
+ */
+ export class TurnEndDiff extends BaseBattleDiff {
+ }
+}
diff --git a/src/core/diffs/TurnStartDiff.ts b/src/core/diffs/TurnStartDiff.ts
new file mode 100644
index 0000000..b0d5811
--- /dev/null
+++ b/src/core/diffs/TurnStartDiff.ts
@@ -0,0 +1,16 @@
+///
+
+module TK.SpaceTac {
+ /**
+ * A turn has started
+ */
+ export class TurnStartDiff extends BaseBattleDiff {
+ readonly play_order: RObjectId[]
+
+ constructor(play_order: Ship[]) {
+ super();
+
+ this.play_order = play_order.map(ship => ship.id);
+ }
+ }
+}
diff --git a/src/ui/battle/BattleInfoBar.spec.ts b/src/ui/battle/BattleInfoBar.spec.ts
index a4534e7..d500675 100644
--- a/src/ui/battle/BattleInfoBar.spec.ts
+++ b/src/ui/battle/BattleInfoBar.spec.ts
@@ -4,7 +4,7 @@ module TK.SpaceTac.UI.Specs {
test.case("shows turn counter and current phase", check => {
const parent = testgame.view.getLayer("test");
- const bar = new BattleInfoBar(parent.getBuilder());
+ const bar = new BattleInfoBar(parent.getBuilder(), { startResolution: () => null });
expect(collectTexts(parent)).toEqual(["Battle"]);
diff --git a/src/ui/battle/BattleInfoBar.ts b/src/ui/battle/BattleInfoBar.ts
index 659446c..6f9ecdb 100644
--- a/src/ui/battle/BattleInfoBar.ts
+++ b/src/ui/battle/BattleInfoBar.ts
@@ -26,20 +26,7 @@ module TK.SpaceTac.UI {
this.title = builder.in(this.container).text("Battle", 0, 0, { center: true, size: 30, shadow: true, color: "#dbeff9" });
- this.planning = new BattleInfoBarPlanning(this.container, () => {
- });
- }
-
- startResolution(): void {
- const startResolution = this.config.startResolution;
- if (startResolution) {
- const message = "Validate all your ship's planning, and proceed to turn resolution?";
- UIConfirmDialog.ask(this.builder.view, message).then(ok => {
- if (ok) {
- startResolution();
- }
- });
- }
+ this.planning = new BattleInfoBarPlanning(this.container, config.startResolution);
}
setPhase(turn: number, phase: BattleInfoBarPhase): void {
@@ -60,16 +47,18 @@ module TK.SpaceTac.UI {
container: UIContainer
turns: UIText
- constructor(parent: UIContainer, startResolution: Function) {
+ constructor(parent: UIContainer, startResolution?: Function) {
this.container = parent.getBuilder().container("planning", 0, 0, false);
const builder = this.container.getBuilder();
- builder.button("battle-buttons-medium", 604, 0, startResolution, "Confirm your planning and start the turn resolution", undefined, {
- center: true,
- text: "Ready",
- text_x: 12,
- text_style: { size: 24, color: "#9fc4d6" }
- });
+ if (startResolution) {
+ builder.button("battle-buttons-medium", 604, 0, startResolution, "Confirm your planning and start the turn resolution", undefined, {
+ center: true,
+ text: "Ready",
+ text_x: 12,
+ text_style: { size: 24, color: "#9fc4d6" }
+ });
+ }
builder.image("battle-infobar-turncounter", 450, 0, true);
this.turns = builder.text("Turn", 450, 0, { center: true, size: 24, color: "#9fc4d6" });
diff --git a/src/ui/battle/BattleView.ts b/src/ui/battle/BattleView.ts
index 3bd6a0f..8c06352 100644
--- a/src/ui/battle/BattleView.ts
+++ b/src/ui/battle/BattleView.ts
@@ -225,9 +225,15 @@ module TK.SpaceTac.UI {
* Start the turn resolution
*/
startResolution(): void {
- // TODO Check we are in planning phase
- // TODO Wait for AI
- // TODO
+ const message = "Validate your whole fleet planning, and proceed to turn resolution?";
+ UIConfirmDialog.ask(this, message).then(ok => {
+ if (ok) {
+ // TODO Check we are in planning phase
+ // TODO Wait for AI
+ // TODO Merge plans
+ this.actual_battle.applyTurnPlan(this.turn_plannings[0].getTurnPlan());
+ }
+ });
}
/**
diff --git a/src/ui/common/UIConfirmDialog.ts b/src/ui/common/UIConfirmDialog.ts
index bfe40e6..6f94d3d 100644
--- a/src/ui/common/UIConfirmDialog.ts
+++ b/src/ui/common/UIConfirmDialog.ts
@@ -9,7 +9,7 @@ module TK.SpaceTac.UI {
constructor(view: BaseView, message: string) {
super(view);
- this.content.text(message, this.width * 0.5, this.height * 0.4, { color: "#9FC4D6", size: 32, shadow: true });
+ this.content.text(message, this.width * 0.5, this.height * 0.4, { color: "#9FC4D6", size: 32, shadow: true, width: 800 });
this.result = new Promise(resolve => {
this.result_resolver = resolve;