1
0
Fork 0

Added end battle conditions and event

This commit is contained in:
Michaël Lemaire 2015-02-09 01:00:00 +01:00
parent 30e6323bf3
commit de81186faf
9 changed files with 170 additions and 13 deletions

View file

@ -3,6 +3,9 @@ module SpaceTac.Game {
// A turn-based battle between fleets
export class Battle {
// Flag indicating if the battle is ended
ended: boolean;
// Log of all battle events
log: BattleLog;
@ -27,6 +30,7 @@ module SpaceTac.Game {
this.playing_ship_index = null;
this.playing_ship = null;
this.first_turn = true;
this.ended = false;
this.fleets.forEach((fleet: Fleet) => {
fleet.setBattle(this);
@ -69,26 +73,76 @@ module SpaceTac.Game {
this.placeFleetShips(this.fleets[1], 800, 300, Math.PI);
}
// Count the number of fleets still alive
countAliveFleets(): number {
var result = 0;
this.fleets.forEach((fleet: Fleet) => {
if (fleet.isAlive()) {
result += 1;
}
});
return result;
}
// Checks end battle conditions, returns true if the battle ended
checkEndBattle(log: boolean = true) {
if (this.ended) {
return true;
}
var alive_fleets = this.countAliveFleets();
if (alive_fleets == 0) {
// It's a draw
this.ended = true;
this.log.add(new EndBattleEvent(null));
} else if (alive_fleets == 1) {
// We have a winner
var winner: Player = null;
this.fleets.forEach((fleet: Fleet) => {
if (fleet.isAlive()) {
winner = fleet.player;
}
});
this.ended = true;
this.log.add(new EndBattleEvent(winner));
}
return this.ended;
}
// End the current ship turn, passing control to the next one in play order
// If at the end of the play order, next turn will start automatically
// Member 'play_order' must be defined before calling this function
advanceToNextShip(log: boolean = true): void {
var previous_ship = this.playing_ship;
if (this.checkEndBattle(log)) {
return;
}
if (this.play_order.length === 0) {
this.playing_ship_index = null;
this.playing_ship = null;
} else {
if (this.playing_ship_index == null) {
this.playing_ship_index = 0;
} else {
this.playing_ship_index += 1;
var i = 0;
do {
if (this.playing_ship_index == null) {
this.playing_ship_index = 0;
} else {
this.playing_ship_index += 1;
}
if (this.playing_ship_index >= this.play_order.length) {
this.playing_ship_index = 0;
this.first_turn = false;
}
this.playing_ship = this.play_order[this.playing_ship_index];
i++;
} while (!this.playing_ship.alive && i < 1000);
if (i >= 1000) {
throw new Error("Infinite loop in advanceToNextShip");
}
if (this.playing_ship_index >= this.play_order.length) {
this.playing_ship_index = 0;
this.first_turn = false;
}
this.playing_ship = this.play_order[this.playing_ship_index];
}
if (this.playing_ship) {
@ -104,6 +158,7 @@ module SpaceTac.Game {
// This will call all necessary initialization steps (initiative, placement...)
// This will not add any event to the battle log
start(): void {
this.ended = false;
this.placeShips();
this.throwInitiative();
this.play_order.forEach((ship: Ship) => {

View file

@ -29,5 +29,16 @@ module SpaceTac.Game {
setBattle(battle: Battle): void {
this.battle = battle;
}
// Check if the fleet still has living ships
isAlive(): boolean {
var count = 0;
this.ships.forEach((ship: Ship) => {
if (ship.alive) {
count += 1;
}
});
return (count > 0);
}
}
}

View file

@ -228,6 +228,14 @@ module SpaceTac.Game {
}
}
// Set the death status on this ship
setDead(log: boolean = true): void {
this.alive = false;
if (log) {
this.addBattleEvent(new DeathEvent(this));
}
}
// Apply damages to hull and/or shield
addDamage(hull: number, shield: number, log: boolean = true): void {
this.setAttribute(this.hull, -hull, true, log);
@ -239,10 +247,7 @@ module SpaceTac.Game {
if (this.hull.current === 0) {
// Ship is dead
this.alive = false;
if (log) {
this.addBattleEvent(new DeathEvent(this));
}
this.setDead(log);
}
}

View file

@ -1,3 +1,5 @@
/// <reference path="BaseLogEvent.ts"/>
module SpaceTac.Game {
"use strict";

View file

@ -1,3 +1,5 @@
/// <reference path="BaseLogEvent.ts"/>
module SpaceTac.Game {
"use strict";

View file

@ -0,0 +1,18 @@
/// <reference path="BaseLogEvent.ts"/>
module SpaceTac.Game {
"use strict";
// Event logged when the battle ended
// This is always the last event of a battle log
export class EndBattleEvent extends BaseLogEvent {
// Winner of the battle
winner: Player;
constructor(winner: Player) {
super("endbattle");
this.winner = winner;
}
}
}

View file

@ -1,3 +1,5 @@
/// <reference path="BaseLogEvent.ts"/>
module SpaceTac.Game {
"use strict";

View file

@ -1,3 +1,5 @@
/// <reference path="BaseLogEvent.ts"/>
module SpaceTac.Game {
"use strict";

View file

@ -106,6 +106,14 @@ module SpaceTac.Game {
expect(battle.playing_ship).toBe(ship2);
expect(battle.playing_ship_index).toBe(0);
// A dead ship is skipped
ship1.alive = false;
battle.advanceToNextShip();
expect(battle.playing_ship).toBe(ship3);
expect(battle.playing_ship_index).toBe(2);
});
it("calls startTurn on ships, with first turn indicator", function () {
@ -138,5 +146,57 @@ module SpaceTac.Game {
battle.advanceToNextShip();
expect(ship1.startTurn).toHaveBeenCalledWith(false);
});
it("detects victory condition and logs a final EndBattleEvent", function () {
var fleet1 = new Fleet();
var fleet2 = new Fleet();
var ship1 = new Ship(fleet1, "F1S1");
var ship2 = new Ship(fleet1, "F1S2");
var ship3 = new Ship(fleet2, "F2S1");
var battle = new Battle(fleet1, fleet2);
battle.start();
expect(battle.ended).toBe(false);
ship1.setDead();
ship2.setDead();
battle.log.clear();
battle.advanceToNextShip();
expect(battle.ended).toBe(true);
expect(battle.log.events.length).toBe(1);
expect(battle.log.events[0].code).toBe("endbattle");
expect((<EndBattleEvent>battle.log.events[0]).winner).not.toBeNull();
expect((<EndBattleEvent>battle.log.events[0]).winner).toBe(fleet2.player);
});
it("handles a draw in end battle", function () {
var fleet1 = new Fleet();
var fleet2 = new Fleet();
var ship1 = new Ship(fleet1, "F1S1");
var ship2 = new Ship(fleet1, "F1S2");
var ship3 = new Ship(fleet2, "F2S1");
var battle = new Battle(fleet1, fleet2);
battle.start();
expect(battle.ended).toBe(false);
ship1.setDead();
ship2.setDead();
ship3.setDead();
battle.log.clear();
battle.advanceToNextShip();
expect(battle.ended).toBe(true);
expect(battle.log.events.length).toBe(1);
expect(battle.log.events[0].code).toBe("endbattle");
expect((<EndBattleEvent>battle.log.events[0]).winner).toBeNull();
});
});
}