diff --git a/src/scripts/game/Battle.ts b/src/scripts/game/Battle.ts
index 0a7a37a..f7c933b 100644
--- a/src/scripts/game/Battle.ts
+++ b/src/scripts/game/Battle.ts
@@ -103,10 +103,17 @@ module SpaceTac.Game {
// Force an injection of events in the battle log to simulate the initial state
// For instance, this may be called after 'start', to use the log subscription system
// to initialize a battle UI
+ // Attributes 'play_order' and 'playing_ship' should be defined before calling this
injectInitialEvents(): void {
- // TODO Simulate initial ship placement
+ var log = this.log;
+
+ // Simulate initial ship placement
+ this.play_order.forEach((ship) => {
+ log.add(new Events.MoveEvent(ship, ship.arena_x, ship.arena_y));
+ });
+
// Simulate game turn
- this.log.add(new Events.ShipChangeEvent(this.playing_ship, this.playing_ship));
+ log.add(new Events.ShipChangeEvent(this.playing_ship, this.playing_ship));
}
// Create a quick random battle, for testing purposes
diff --git a/src/scripts/game/BattleLog.ts b/src/scripts/game/BattleLog.ts
index 3975e48..8115714 100644
--- a/src/scripts/game/BattleLog.ts
+++ b/src/scripts/game/BattleLog.ts
@@ -6,14 +6,37 @@ module SpaceTac.Game {
// Full list of battle events
events: Events.BaseLogEvent[];
+ // List of subscribers
+ private subscribers: Function[];
+
// Create an initially empty log
constructor() {
this.events = [];
+ this.subscribers = [];
}
// Add a battle event to the log
add(event: Events.BaseLogEvent) {
this.events.push(event);
+
+ this.subscribers.forEach((subscriber) => {
+ subscriber(event);
+ });
+ }
+
+ // Subscribe a callback to receive further events
+ subscribe(callback: (event: Events.BaseLogEvent) => void): Function {
+ this.subscribers.push(callback);
+ return callback;
+ }
+
+ // Unsubscribe a callback
+ // Pass the value returned by 'subscribe' as argument
+ unsubscribe(callback: Function): void {
+ var index = this.subscribers.indexOf(callback);
+ if (index >= 0) {
+ this.subscribers.splice(index, 1);
+ }
}
}
}
\ No newline at end of file
diff --git a/src/scripts/game/events/MoveEvent.ts b/src/scripts/game/events/MoveEvent.ts
new file mode 100644
index 0000000..4e821b9
--- /dev/null
+++ b/src/scripts/game/events/MoveEvent.ts
@@ -0,0 +1,8 @@
+module SpaceTac.Game.Events {
+ // Event logged when a ship moves
+ export class MoveEvent extends BaseLogEvent {
+ constructor(ship: Ship, x: number, y: number) {
+ super("move", ship, Target.newFromLocation(x, y));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/scripts/specs/Battle.spec.ts b/src/scripts/game/specs/Battle.spec.ts
similarity index 98%
rename from src/scripts/specs/Battle.spec.ts
rename to src/scripts/game/specs/Battle.spec.ts
index 7b50d64..67a599b 100644
--- a/src/scripts/specs/Battle.spec.ts
+++ b/src/scripts/game/specs/Battle.spec.ts
@@ -1,4 +1,4 @@
-///
+///
module SpaceTac.Specs {
describe("Battle", function () {
diff --git a/src/scripts/specs/BattleLog.spec.ts b/src/scripts/game/specs/BattleLog.spec.ts
similarity index 50%
rename from src/scripts/specs/BattleLog.spec.ts
rename to src/scripts/game/specs/BattleLog.spec.ts
index e5f10f5..7f1e1d3 100644
--- a/src/scripts/specs/BattleLog.spec.ts
+++ b/src/scripts/game/specs/BattleLog.spec.ts
@@ -1,3 +1,5 @@
+///
+
module SpaceTac.Specs {
// Check a single game log event
@@ -27,7 +29,34 @@ module SpaceTac.Specs {
}
}
+ // Fake event
+ class FakeEvent extends Game.Events.BaseLogEvent {
+ constructor() {
+ super("fake");
+ }
+ }
+
describe("BattleLog", function () {
+ it("forwards events to subscribers, until unsubscribe", function () {
+ var log = new Game.BattleLog();
+ var received = [];
+ var fake = new FakeEvent();
+
+ var sub = log.subscribe(function (event) {
+ received.push(event);
+ });
+
+ log.add(fake);
+ expect(received).toEqual([fake]);
+
+ log.add(fake);
+ expect(received).toEqual([fake, fake]);
+
+ log.unsubscribe(sub);
+ log.add(fake);
+ expect(received).toEqual([fake, fake]);
+ });
+
it("logs ship change events", function () {
var battle = Game.Battle.newQuickRandom();
expect(battle.log.events.length).toBe(0);
@@ -36,5 +65,19 @@ module SpaceTac.Specs {
expect(battle.log.events.length).toBe(1);
checkEvent(battle.log.events[0], battle.play_order[0], "ship_change", battle.play_order[1]);
});
+
+ it("can receive simulated initial state events", function (){
+ var battle = Game.Battle.newQuickRandom();
+
+ expect(battle.log.events.length).toBe(0);
+
+ battle.injectInitialEvents();
+
+ expect(battle.log.events.length).toBe(9);
+ for (var i = 0; i < 8; i++) {
+ checkEvent(battle.log.events[i], battle.play_order[i], "move", null, battle.play_order[i].arena_x, battle.play_order[i].arena_y);
+ }
+ checkEvent(battle.log.events[8], battle.playing_ship, "ship_change", battle.playing_ship);
+ });
});
}
\ No newline at end of file
diff --git a/src/scripts/specs/Ship.spec.ts b/src/scripts/game/specs/Ship.spec.ts
similarity index 95%
rename from src/scripts/specs/Ship.spec.ts
rename to src/scripts/game/specs/Ship.spec.ts
index 3662fa8..ca90d42 100644
--- a/src/scripts/specs/Ship.spec.ts
+++ b/src/scripts/game/specs/Ship.spec.ts
@@ -1,4 +1,4 @@
-///
+///
module SpaceTac.Specs {
describe("Ship", function(){
diff --git a/src/scripts/view/BattleView.ts b/src/scripts/view/BattleView.ts
index 6da2ae6..c04b772 100644
--- a/src/scripts/view/BattleView.ts
+++ b/src/scripts/view/BattleView.ts
@@ -17,15 +17,30 @@ module SpaceTac.View {
// Targetting mode (null if we're not in this mode)
targetting: Targetting;
+ // Card to display current playing ship
+ card_playing: Widgets.ShipCard;
+
+ // Card to display hovered ship
+ card_hovered: Widgets.ShipCard;
+
+ // Currently hovered ship
+ ship_hovered: Game.Ship;
+
+ // Subscription to the battle log
+ log_subscription: any;
+
// Init the view, binding it to a specific battle
init(player, battle) {
this.player = player;
this.battle = battle;
this.targetting = null;
+ this.ship_hovered = null;
+ this.log_subscription = null;
}
// Create view graphics
create() {
+ var battleview = this;
var game = this.game;
var player = this.player;
@@ -37,28 +52,83 @@ module SpaceTac.View {
game.add.existing(this.arena);
var arena = this.arena;
+ this.card_playing = new Widgets.ShipCard(this, 500, 0);
+ this.card_hovered = new Widgets.ShipCard(this, 500, 300);
+
game.stage.backgroundColor = 0x000000;
// Add ship buttons to UI
- this.battle.play_order.forEach(function(ship: Game.Ship, rank: number){
- new Widgets.ShipListItem(ui, 0, rank * 50, ship.getPlayer() === player);
+ this.battle.play_order.forEach(function (ship: Game.Ship, rank: number) {
+ new Widgets.ShipListItem(battleview, 0, rank * 50, ship, ship.getPlayer() === player);
});
// Add ship sprites to arena
- this.battle.play_order.forEach(function(ship: Game.Ship){
- new Arena.ShipArenaSprite(arena, ship);
+ this.battle.play_order.forEach(function (ship: Game.Ship) {
+ new Arena.ShipArenaSprite(battleview, ship);
});
+
+ // Subscribe to log events
+ this.battle.log.subscribe((event) => {
+ battleview.processBattleEvent(event);
+ });
+ this.battle.injectInitialEvents();
}
// Leaving the view, we unbind the battle
shutdown() {
+ if (this.log_subscription) {
+ this.battle.log.unsubscribe(this.log_subscription);
+ this.log_subscription = null;
+ }
+
+ if (this.ui) {
+ this.ui.destroy();
+ this.ui = null;
+ }
+
+ if (this.arena) {
+ this.arena.destroy();
+ this.arena = null;
+ }
+
+ if (this.card_playing) {
+ this.card_playing.destroy();
+ this.card_playing = null;
+ }
+
+ if (this.card_hovered) {
+ this.card_hovered.destroy();
+ this.card_hovered = null;
+ }
+
this.battle = null;
+ }
- this.ui.destroy();
- this.ui = null;
+ // Process a BaseLogEvent
+ processBattleEvent(event: Game.Events.BaseLogEvent) {
+ console.log("Battle event", event);
+ if (event.code == "ship_change") {
+ // Playing ship changed
+ this.card_playing.setShip(event.target.ship);
+ }
+ }
- this.arena.destroy();
- this.arena = null;
+ // Method called when cursor starts hovering over a ship (or its icon)
+ cursorOnShip(ship: Game.Ship): void {
+ this.setShipHovered(ship);
+ }
+
+ // Method called when cursor stops hovering over a ship (or its icon)
+ cursorOffShip(ship: Game.Ship): void {
+ if (this.ship_hovered === ship) {
+ this.setShipHovered(null);
+ }
+ }
+
+ // Set the currently hovered ship
+ setShipHovered(ship: Game.Ship): void {
+ this.ship_hovered = ship;
+ this.card_hovered.setShip(ship);
}
// Enter targetting mode
diff --git a/src/scripts/view/arena/ShipArenaSprite.ts b/src/scripts/view/arena/ShipArenaSprite.ts
index adc5f27..4bb62ff 100644
--- a/src/scripts/view/arena/ShipArenaSprite.ts
+++ b/src/scripts/view/arena/ShipArenaSprite.ts
@@ -1,14 +1,21 @@
-module SpaceTac.Arena {
+module SpaceTac.View.Arena {
// Ship sprite in the arena (BattleView)
- export class ShipArenaSprite extends Phaser.Sprite {
- constructor(arena: Phaser.Group, ship: Game.Ship) {
- super(arena.game, ship.arena_x, ship.arena_y, "arena-ship");
+ export class ShipArenaSprite extends Phaser.Button {
+ constructor(battleview: BattleView, ship: Game.Ship) {
+ super(battleview.game, ship.arena_x, ship.arena_y, "arena-ship");
this.scale.set(0.1, 0.1);
this.rotation = ship.arena_angle;
this.anchor.set(0.5, 0.5);
- arena.add(this);
+ battleview.arena.add(this);
+
+ this.onInputOver.add(() => {
+ battleview.cursorOnShip(ship);
+ });
+ this.onInputOut.add(() => {
+ battleview.cursorOffShip(ship);
+ });
}
}
}
diff --git a/src/scripts/view/widgets/ShipCard.ts b/src/scripts/view/widgets/ShipCard.ts
new file mode 100644
index 0000000..08f24b2
--- /dev/null
+++ b/src/scripts/view/widgets/ShipCard.ts
@@ -0,0 +1,23 @@
+module SpaceTac.View.Widgets {
+ // Card to display detailed information about a ship
+ export class ShipCard extends Phaser.Sprite {
+ // Displayed ship
+ private ship: Game.Ship;
+
+ // Build an empty ship card
+ constructor(battleview: BattleView, x: number, y: number) {
+ super(battleview.game, x, y, "ui-ship-card");
+
+ this.ship = null;
+ this.visible = false;
+
+ battleview.ui.add(this);
+ }
+
+ // Set the currently displayed ship (null to hide)
+ setShip(ship: Game.Ship) {
+ this.ship = ship;
+ this.visible = (ship !== null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/scripts/view/widgets/ShipListItem.ts b/src/scripts/view/widgets/ShipListItem.ts
index 5d3f872..9ac3368 100644
--- a/src/scripts/view/widgets/ShipListItem.ts
+++ b/src/scripts/view/widgets/ShipListItem.ts
@@ -1,10 +1,22 @@
module SpaceTac.View.Widgets {
// One item in a ship list (used in BattleView)
export class ShipListItem extends Phaser.Button {
+ // Reference to the ship game object
+ private ship: Game.Ship;
+
// Create a ship button for the battle ship list
- constructor(ui: UIGroup, x: number, y: number, owned: boolean) {
- super(ui.game, x, y, owned ? 'ui-shiplist-own' : 'ui-shiplist-enemy');
- ui.add(this);
+ constructor(battleview: BattleView, x: number, y: number, ship:Game.Ship, owned: boolean) {
+ this.ship = ship;
+
+ super(battleview.game, x, y, owned ? 'ui-shiplist-own' : 'ui-shiplist-enemy');
+ battleview.ui.add(this);
+
+ this.onInputOver.add(() => {
+ battleview.cursorOnShip(ship);
+ });
+ this.onInputOut.add(() => {
+ battleview.cursorOffShip(ship);
+ });
}
}
}
\ No newline at end of file