diff --git a/src/scripts/game/actions/BaseAction.ts b/src/scripts/game/actions/BaseAction.ts index 4d59310..f286db8 100644 --- a/src/scripts/game/actions/BaseAction.ts +++ b/src/scripts/game/actions/BaseAction.ts @@ -37,5 +37,19 @@ module SpaceTac.Game { checkShipTarget(battle: Battle, ship: Ship, target: Target): Target { return null; } + + // Apply an action, returning true if it was successful + apply(battle: Battle, ship: Ship, target: Target): boolean { + target = this.checkTarget(battle, ship, target); + if (!target) { + return false; + } + return this.customApply(battle, ship, target); + } + + // Method to reimplement to apply a action + protected customApply(battle: Battle, ship: Ship, target: Target): boolean { + return false; + } } } \ No newline at end of file diff --git a/src/scripts/game/actions/MoveAction.ts b/src/scripts/game/actions/MoveAction.ts index e91aff7..647b75c 100644 --- a/src/scripts/game/actions/MoveAction.ts +++ b/src/scripts/game/actions/MoveAction.ts @@ -14,5 +14,10 @@ module SpaceTac.Game { var coords = ship.getLongestMove(target.x, target.y); return Target.newFromLocation(coords[0], coords[1]); } + + protected customApply(battle: Battle, ship: Ship, target: Target): boolean { + ship.moveTo(target.x, target.y); + return true; + } } } \ No newline at end of file diff --git a/src/scripts/view/battle/ActionBar.ts b/src/scripts/view/battle/ActionBar.ts new file mode 100644 index 0000000..45facbe --- /dev/null +++ b/src/scripts/view/battle/ActionBar.ts @@ -0,0 +1,54 @@ +module SpaceTac.View { + // Bar with all available action icons displayed + export class ActionBar extends Phaser.Group { + // Link to the parent battleview + battleview: BattleView; + + // List of action icons + actions: ActionIcon[]; + + // Create an empty action bar + constructor(battleview: BattleView) { + this.battleview = battleview; + this.actions = []; + + super(battleview.game, battleview.ui); + battleview.ui.add(this); + + this.update(); + } + + // Update the bar status (and position) + update() { + super.update(); + + this.x = 100; + } + + // Clear the action icons + clearAll(): void { + this.actions.forEach((action) => { + action.destroy(); + }); + this.actions = []; + } + + // Add an action icon + addAction(ship: Game.Ship, action: Game.BaseAction): ActionIcon { + var icon = new ActionIcon(this, this.actions.length * 50, 0, ship, action); + this.actions.push(icon); + return icon; + } + + // Set action icons from selected ship + setShip(ship: Game.Ship): void { + var action_bar = this; + this.clearAll(); + + var actions = ship.getAvailableActions(); + actions.forEach((action) => { + action_bar.addAction(ship, action); + }); + } + } +} \ No newline at end of file diff --git a/src/scripts/view/battle/ActionIcon.ts b/src/scripts/view/battle/ActionIcon.ts index 245b3ba..808e1a6 100644 --- a/src/scripts/view/battle/ActionIcon.ts +++ b/src/scripts/view/battle/ActionIcon.ts @@ -1,8 +1,43 @@ module SpaceTac.View { // Icon to activate a ship capability (move, fire...) export class ActionIcon extends Phaser.Button { - constructor(battleview: BattleView, x: number, y:number, code: string) { - super(battleview.game, x, y, 'action-' + code); + + // Link to the parent battle view + battleview: BattleView; + + // Related ship + ship: Game.Ship; + + // Related game action + action: Game.BaseAction; + + // Create an icon for a single ship action + constructor(bar: ActionBar, x: number, y:number, ship: Game.Ship, action: Game.BaseAction) { + this.battleview = bar.battleview; + this.ship = ship; + this.action = action; + + super(bar.game, x, y, 'action-' + action.code); + bar.add(this); + + this.onInputUp.add(() => { + this.processClick(); + }, this); + } + + // Process a click event on the action icon + processClick() { + console.log("Action started", this.action); + + var targetting = this.battleview.enterTargettingMode(); + targetting.targetSelected.add(this.processTarget, this); + } + + // Receive a target for the action + processTarget(target: Game.Target) { + console.log("Action target", this.action, target); + + this.action.apply(this.battleview.battle, this.ship, target); } } } \ No newline at end of file diff --git a/src/scripts/view/battle/Arena.ts b/src/scripts/view/battle/Arena.ts index 2e6b508..8ede1ec 100644 --- a/src/scripts/view/battle/Arena.ts +++ b/src/scripts/view/battle/Arena.ts @@ -2,17 +2,21 @@ module SpaceTac.View { // Graphical representation of a battle // This is the area in the BattleView that will display ships with their real positions export class Arena extends Phaser.Group { - background: Phaser.Image; + background: Phaser.Button; private input_callback: any; constructor(battleview: BattleView) { super(battleview.game); - var background = new Phaser.Image(battleview.game, 0, 0, 'ui-arena-background'); + var background = new Phaser.Button(battleview.game, 0, 0, 'ui-arena-background'); background.scale.set(5, 5); - background.inputEnabled = true; this.background = background; + // Capture clicks on background + background.onInputUp.add(() => { + battleview.cursorClicked(); + }); + // Watch mouse move to capture hovering over background this.input_callback = this.game.input.addMoveCallback((pointer) => { var point = new Phaser.Point(); diff --git a/src/scripts/view/battle/BattleView.ts b/src/scripts/view/battle/BattleView.ts index e950a27..be866bc 100644 --- a/src/scripts/view/battle/BattleView.ts +++ b/src/scripts/view/battle/BattleView.ts @@ -23,6 +23,9 @@ module SpaceTac.View { // Card to display hovered ship card_hovered: ShipCard; + // Action bar + action_bar: ActionBar; + // Currently hovered ship ship_hovered: Game.Ship; @@ -44,17 +47,21 @@ module SpaceTac.View { var game = this.game; var player = this.player; + game.stage.backgroundColor = 0x000000; + + // Add arena (local map) this.arena = new Arena(battleview); game.add.existing(this.arena); + // Add UI layer this.ui = new UIGroup(game); game.add.existing(this.ui); + // Add UI elements + this.action_bar = new ActionBar(this); this.card_playing = new ShipCard(this, 500, 0); this.card_hovered = new 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 ShipListItem(battleview, 0, rank * 50, ship, ship.getPlayer() === player); @@ -71,6 +78,8 @@ module SpaceTac.View { // Leaving the view, we unbind the battle shutdown() { + this.exitTargettingMode(); + if (this.log_processor) { this.log_processor.destroy(); this.log_processor = null; @@ -115,6 +124,16 @@ module SpaceTac.View { cursorInSpace(x: number, y: number): void { if (!this.ship_hovered) { console.log("In space", x, y); + if (this.targetting) { + this.targetting.setTargetSpace(x, y); + } + } + } + + // Method called when cursor has been clicked (in space or on a ship) + cursorClicked(): void { + if (this.targetting) { + this.targetting.validate(); } } @@ -122,17 +141,27 @@ module SpaceTac.View { setShipHovered(ship: Game.Ship): void { this.ship_hovered = ship; this.card_hovered.setShip(ship); + if (this.targetting && ship) { + this.targetting.setTargetShip(ship); + } } // Enter targetting mode // While in this mode, the Targetting object will receive hover and click events, and handle them enterTargettingMode(): Targetting { + if (this.targetting) { + this.exitTargettingMode(); + } + this.targetting = new Targetting(this); return this.targetting; } // Exit targetting mode exitTargettingMode(): void { + if (this.targetting) { + this.targetting.destroy(); + } this.targetting = null; } } diff --git a/src/scripts/view/battle/LogProcessor.ts b/src/scripts/view/battle/LogProcessor.ts index 0dfe63b..2308ee2 100644 --- a/src/scripts/view/battle/LogProcessor.ts +++ b/src/scripts/view/battle/LogProcessor.ts @@ -29,9 +29,16 @@ module SpaceTac.View { // Process a BaseLogEvent processBattleEvent(event: Game.BaseLogEvent) { console.log("Battle event", event); - if (event.code == "ship_change") { - // Playing ship changed - this.view.card_playing.setShip(event.target.ship); + + switch (event.code) { + case "ship_change": + // Playing ship changed + this.view.card_playing.setShip(event.target.ship); + this.view.action_bar.setShip(event.target.ship); + break; + case "move": + // TODO A ship moved + break; } } diff --git a/src/scripts/view/battle/ShipArenaSprite.ts b/src/scripts/view/battle/ShipArenaSprite.ts index c98e4cd..41aa2aa 100644 --- a/src/scripts/view/battle/ShipArenaSprite.ts +++ b/src/scripts/view/battle/ShipArenaSprite.ts @@ -17,6 +17,9 @@ module SpaceTac.View { this.onInputOut.add(() => { battleview.cursorOffShip(ship); }); + this.onInputUp.add(() => { + battleview.cursorClicked(); + }); } } } diff --git a/src/scripts/view/battle/Targetting.ts b/src/scripts/view/battle/Targetting.ts index 8d27fa4..a9c5583 100644 --- a/src/scripts/view/battle/Targetting.ts +++ b/src/scripts/view/battle/Targetting.ts @@ -1,12 +1,48 @@ module SpaceTac.View { // Targetting system - // Allows to pick a target for a capability + // Allows to pick a target for an action export class Targetting { // Access to the parent battle view private battleview: BattleView; + // Current target + private target: Game.Target; + + // Signal to receive hovering events + targetHovered: Phaser.Signal; + + // Signal to receive targetting events + targetSelected: Phaser.Signal; + + // Create a default targetting mode constructor(battleview: BattleView) { this.battleview = battleview; + this.targetHovered = new Phaser.Signal(); + this.targetSelected = new Phaser.Signal(); + } + + // Destructor + destroy(): void { + this.targetHovered.dispose(); + this.targetSelected.dispose(); + } + + // Set the current target ship (when hovered) + setTargetShip(ship: Game.Ship): void { + this.target = Game.Target.newFromShip(ship); + this.targetHovered.dispatch(this.target); + } + + // Set the current target in space (when hovered) + setTargetSpace(x: number, y: number): void { + this.target = Game.Target.newFromLocation(x, y); + this.targetHovered.dispatch(this.target); + } + + // Validate the current target (when clicked) + // This will broadcast the targetSelected signal + validate(): void { + this.targetSelected.dispatch(this.target); } } } \ No newline at end of file diff --git a/src/scripts/view/specs/Targetting.spec.ts b/src/scripts/view/specs/Targetting.spec.ts new file mode 100644 index 0000000..cd12c5f --- /dev/null +++ b/src/scripts/view/specs/Targetting.spec.ts @@ -0,0 +1,26 @@ +/// + +module SpaceTac.View { + describe("Targetting", () => { + it("broadcasts hovering and selection events", () => { + var targetting = new Targetting(null); + + var hovered = []; + var selected = []; + targetting.targetHovered.add((target: Game.Target) => { + hovered.push(target); + }); + targetting.targetSelected.add((target: Game.Target) => { + selected.push(target); + }); + + targetting.setTargetSpace(1, 2); + expect(hovered).toEqual([Game.Target.newFromLocation(1, 2)]); + expect(selected).toEqual([]); + + targetting.validate(); + expect(hovered).toEqual([Game.Target.newFromLocation(1, 2)]); + expect(selected).toEqual([Game.Target.newFromLocation(1, 2)]); + }); + }); +} \ No newline at end of file