From 97771a9b0aa2c4adc83eaab5099fd03471494696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Mon, 16 Feb 2015 01:00:00 +0100 Subject: [PATCH] Added player interaction status and icon --- src/assets/images/battle/waiting.png | Bin 0 -> 3513 bytes src/scripts/game/Battle.ts | 31 ++++++++++++++++++++-- src/scripts/game/Player.ts | 4 +++ src/scripts/game/ai/AbstractAI.ts | 17 ++++++++++++ src/scripts/game/ai/BullyAI.ts | 11 ++++++++ src/scripts/view/Main.ts | 2 +- src/scripts/view/Preload.ts | 3 ++- src/scripts/view/battle/ActionBar.ts | 14 ++++++---- src/scripts/view/battle/BattleView.ts | 24 +++++++++++++++++ src/scripts/view/battle/LogProcessor.ts | 2 ++ src/scripts/view/specs/BattleView.spec.ts | 2 +- 11 files changed, 100 insertions(+), 10 deletions(-) create mode 100644 src/assets/images/battle/waiting.png create mode 100644 src/scripts/game/ai/AbstractAI.ts create mode 100644 src/scripts/game/ai/BullyAI.ts diff --git a/src/assets/images/battle/waiting.png b/src/assets/images/battle/waiting.png new file mode 100644 index 0000000000000000000000000000000000000000..5c1b7f0686cea164c03a3bc7a2d7f4a37e8bca51 GIT binary patch literal 3513 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 literal 0 HcmV?d00001 diff --git a/src/scripts/game/Battle.ts b/src/scripts/game/Battle.ts index 5091d9f..10e6803 100644 --- a/src/scripts/game/Battle.ts +++ b/src/scripts/game/Battle.ts @@ -41,15 +41,30 @@ module SpaceTac.Game { } // Create a quick random battle, for testing purposes - static newQuickRandom(): Battle { + static newQuickRandom(with_ai: boolean = false): Battle { var player1 = Player.newQuickRandom("John"); var player2 = Player.newQuickRandom("Carl"); var result = new Battle(player1.fleet, player2.fleet); + if (with_ai) { + player2.ai = new AI.BullyAI(player2.fleet); + } result.start(); return result; } + // Check if a player is able to play + // This can be used by the UI to determine if player interaction is allowed + canPlay(player: Player): boolean { + if (this.ended) { + return false; + } else if (this.playing_ship.getPlayer() === player) { + return this.playing_ship.isAbleToPlay(); + } else { + return false; + } + } + // Create play order, performing an initiative throw throwInitiative(gen: RandomGenerator = new RandomGenerator()): void { var play_order: Ship[] = []; @@ -160,6 +175,18 @@ module SpaceTac.Game { if (this.playing_ship) { this.playing_ship.startTurn(this.first_turn); + + if (!this.playing_ship.isAbleToPlay()) { + // If the ship is not able to play, wait a little, then advance to the next one + setTimeout(() => { + this.advanceToNextShip(log); + }, 2000); + } else if (this.playing_ship.getPlayer().ai) { + // TODO If the ship is managed by an AI, let it get to work + setTimeout(() => { + this.advanceToNextShip(log); + }, 2000); + } } if (log) { @@ -178,7 +205,7 @@ module SpaceTac.Game { ship.updateAttributes(); ship.restoreHealth(); }); - this.advanceToNextShip(false); + this.advanceToNextShip(); } // Force an injection of events in the battle log to simulate the initial state diff --git a/src/scripts/game/Player.ts b/src/scripts/game/Player.ts index 7edf8d3..ed64e04 100644 --- a/src/scripts/game/Player.ts +++ b/src/scripts/game/Player.ts @@ -6,9 +6,13 @@ module SpaceTac.Game { // Current fleet fleet: Fleet; + // AI playing (null for human player) + ai: AI.AbstractAI; + // Create a player, with an empty fleet constructor() { this.fleet = new Fleet(this); + this.ai = null; } // Create a quick random player, with a fleet, for testing purposes diff --git a/src/scripts/game/ai/AbstractAI.ts b/src/scripts/game/ai/AbstractAI.ts new file mode 100644 index 0000000..18433b7 --- /dev/null +++ b/src/scripts/game/ai/AbstractAI.ts @@ -0,0 +1,17 @@ +module SpaceTac.Game.AI { + "use strict"; + + // Base class for all Artificial Intelligence interaction + export class AbstractAI { + // The battle this AI is involved in + battle: Battle; + + // The fleet controlled by this AI + fleet: Fleet; + + constructor(fleet: Fleet) { + this.fleet = fleet; + this.battle = fleet.battle; + } + } +} diff --git a/src/scripts/game/ai/BullyAI.ts b/src/scripts/game/ai/BullyAI.ts new file mode 100644 index 0000000..4662c5b --- /dev/null +++ b/src/scripts/game/ai/BullyAI.ts @@ -0,0 +1,11 @@ +/// +module SpaceTac.Game.AI { + "use strict"; + + // Basic Artificial Intelligence, with a tendency to move forward and shoot the nearest enemy + export class BullyAI extends AbstractAI { + constructor(fleet: Fleet) { + super(fleet); + } + } +} diff --git a/src/scripts/view/Main.ts b/src/scripts/view/Main.ts index 709a6e7..2b3b95b 100644 --- a/src/scripts/view/Main.ts +++ b/src/scripts/view/Main.ts @@ -4,7 +4,7 @@ module SpaceTac.View { export class Main extends Phaser.State { create() { // Switch to a test battle - var battle = Game.Battle.newQuickRandom(); + var battle = Game.Battle.newQuickRandom(true); this.game.state.start("battle", true, false, battle.fleets[0].player, battle); } } diff --git a/src/scripts/view/Preload.ts b/src/scripts/view/Preload.ts index 022a46f..6e130c3 100644 --- a/src/scripts/view/Preload.ts +++ b/src/scripts/view/Preload.ts @@ -11,12 +11,13 @@ module SpaceTac.View { this.load.setPreloadSprite(this.preloadBar); // Load assets - this.loadImage("battle/background.jpg"); + this.loadImage("battle/waiting.png"); this.loadImage("battle/shiplist-base.png"); this.loadImage("battle/shiplist-normal.png"); this.loadImage("battle/shiplist-playing.png"); this.loadImage("battle/shiplist-own.png"); this.loadImage("battle/shiplist-enemy.png"); + this.loadImage("battle/background.jpg"); this.loadImage("battle/arena/background.png"); this.loadImage("battle/actionbar.png"); this.loadImage("battle/action-inactive.png"); diff --git a/src/scripts/view/battle/ActionBar.ts b/src/scripts/view/battle/ActionBar.ts index 1222145..731b4e7 100644 --- a/src/scripts/view/battle/ActionBar.ts +++ b/src/scripts/view/battle/ActionBar.ts @@ -60,12 +60,16 @@ module SpaceTac.View { var action_bar = this; this.clearAll(); - var actions = ship.getAvailableActions(); - actions.forEach((action: Game.BaseAction) => { - action_bar.addAction(ship, action); - }); + if (ship.getPlayer() === this.battleview.player) { + var actions = ship.getAvailableActions(); + actions.forEach((action: Game.BaseAction) => { + action_bar.addAction(ship, action); + }); - this.ship = ship; + this.ship = ship; + } else { + this.ship = null; + } this.updateActionPoints(); } diff --git a/src/scripts/view/battle/BattleView.ts b/src/scripts/view/battle/BattleView.ts index 35cea10..a82f6c1 100644 --- a/src/scripts/view/battle/BattleView.ts +++ b/src/scripts/view/battle/BattleView.ts @@ -40,6 +40,12 @@ module SpaceTac.View { // Subscription to the battle log log_processor: LogProcessor; + // True if player interaction is allowed + interacting: boolean; + + // Indicator of interaction disabled + icon_waiting: Phaser.Image; + // Init the view, binding it to a specific battle init(player: Game.Player, battle: Game.Battle) { this.player = player; @@ -74,6 +80,11 @@ module SpaceTac.View { this.card_playing = new ShipCard(this, 1060, 130); this.card_hovered = new ShipCard(this, 1060, 430); + this.icon_waiting = new Phaser.Image(this.game, 640, 360, "battle-waiting", 0); + this.icon_waiting.anchor.set(0.5, 0.5); + game.add.existing(this.icon_waiting); + game.tweens.create(this.icon_waiting).to({"angle": 360}, 3000).repeat(-1).start(); + // Start processing the battle log this.log_processor = new LogProcessor(this); } @@ -153,9 +164,22 @@ module SpaceTac.View { } } + // Enable or disable the global player interaction + // Disable interaction when it is the AI turn, or when the current ship can't play + setInteractionEnabled(enabled: boolean): void { + this.exitTargettingMode(); + this.interacting = enabled; + + this.icon_waiting.visible = !this.interacting; + } + // Enter targetting mode // While in this mode, the Targetting object will receive hover and click events, and handle them enterTargettingMode(): Targetting { + if (!this.interacting) { + return null; + } + if (this.targetting) { this.exitTargettingMode(); } diff --git a/src/scripts/view/battle/LogProcessor.ts b/src/scripts/view/battle/LogProcessor.ts index 9cc9ab3..1d3dc1a 100644 --- a/src/scripts/view/battle/LogProcessor.ts +++ b/src/scripts/view/battle/LogProcessor.ts @@ -62,6 +62,8 @@ module SpaceTac.View { this.view.ship_list.setPlaying(event.target.ship); this.view.card_playing.setShip(event.target.ship); this.view.action_bar.setShip(event.target.ship); + + this.view.setInteractionEnabled(this.battle.canPlay(this.view.player)); } // Damage to ship diff --git a/src/scripts/view/specs/BattleView.spec.ts b/src/scripts/view/specs/BattleView.spec.ts index 8fe0529..50bfd6d 100644 --- a/src/scripts/view/specs/BattleView.spec.ts +++ b/src/scripts/view/specs/BattleView.spec.ts @@ -8,7 +8,7 @@ module SpaceTac.View.Specs { export function inbattleview_it(desc: string, func: (battleview: BattleView) => void) { var battleview = new BattleView(); var battle = Game.Battle.newQuickRandom(); - var player = battle.fleets[0].player; + var player = battle.playing_ship.getPlayer(); ingame_it(desc, (game: Phaser.Game, state: Phaser.State) => { func(battleview); }, battleview, player, battle);