diff --git a/README.md b/README.md index e88f0b3..ba7d5ce 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ If you want to build on your computer, clone the repository, then run: ./spacetac install # Install dependencies ./spacetac run build # Build the final JS - ./spacetac run pack # Pack the images and sounds + ./spacetac run atlas # Pack the images and sounds ./spacetac test # Run unit tests ./spacetac start # Start development server, and open game in web browser diff --git a/TODO.md b/TODO.md index 950a25e..12ac7df 100644 --- a/TODO.md +++ b/TODO.md @@ -19,7 +19,7 @@ Map/story * Allow to cancel secondary missions * Forbid to end up with more than 5 ships in the fleet because of escorts * Fix problems when several dialogs are active at the same time -* Handle case where cargo is full to give a reward (give money ?) +* Handle case where cargo is full to give a reward (give money?) Character sheet --------------- @@ -39,13 +39,13 @@ Battle * Add quick animation of playing ship indicator, on ship change * Display a hint when a move-fire simulation failed (cannot enter exclusion area for example) * Display effects description instead of attribute changes -* Display radius and power usage hints for area effects on action icon hover + add confirmation ? +* Display radius and power usage hints for area effects on action icon hover + add confirmation? * Any displayed info should be based on a ship copy stored in ArenaShip, and in sync with current log index (not the game state ship) * Add engine trail effect, and sound * Fix targetting not resetting on current cursor location when using keyboard shortcuts * Allow to skip animations, and allow no animation mode -* Find incentives to move from starting position (permanent drones or anomalies ?) -* Add a "loot all" button, disable the loot button if there is no loot +* Find incentives to move from starting position (permanent drones or anomalies?) +* Add a "loot all" button (on the character sheet or outcome dialog?) * Do not focus on ship while targetting for area effects (dissociate hover and target) * Repair drone has its activation effect sometimes displayed as permanent effect on ships in the radius * Merge identical sticky effects @@ -110,7 +110,7 @@ Postponed * Replays * Multiplayer/co-op * Formation or deployment phase -* Add ship personality (with icons to identify ?), with reaction dialogs +* Add ship personality (with icons to identify?), with reaction dialogs * New battle internal flow: any game state change should be done through revertable events * Animated arena background, instead of big picture * Hide enemy information (shield, hull, weapons), until they are in play, or until a "spy" effect is used diff --git a/out/assets/images/battle/outcome/title-defeat.png b/graphics/exported/battle/outcome/title-defeat.png similarity index 100% rename from out/assets/images/battle/outcome/title-defeat.png rename to graphics/exported/battle/outcome/title-defeat.png diff --git a/out/assets/images/battle/outcome/title-victory.png b/graphics/exported/battle/outcome/title-victory.png similarity index 100% rename from out/assets/images/battle/outcome/title-victory.png rename to graphics/exported/battle/outcome/title-victory.png diff --git a/graphics/exported/translucent.png b/graphics/exported/translucent.png new file mode 100644 index 0000000..0df5f12 Binary files /dev/null and b/graphics/exported/translucent.png differ diff --git a/out/assets/images/battle/outcome/button-loot.png b/out/assets/images/battle/outcome/button-loot.png deleted file mode 100644 index fd3ff0f..0000000 Binary files a/out/assets/images/battle/outcome/button-loot.png and /dev/null differ diff --git a/out/assets/images/battle/outcome/button-map.png b/out/assets/images/battle/outcome/button-map.png deleted file mode 100644 index 9cf1906..0000000 Binary files a/out/assets/images/battle/outcome/button-map.png and /dev/null differ diff --git a/out/assets/images/battle/outcome/button-menu.png b/out/assets/images/battle/outcome/button-menu.png deleted file mode 100644 index 3ba37d1..0000000 Binary files a/out/assets/images/battle/outcome/button-menu.png and /dev/null differ diff --git a/out/assets/images/battle/outcome/button-revert.png b/out/assets/images/battle/outcome/button-revert.png deleted file mode 100644 index f1892b8..0000000 Binary files a/out/assets/images/battle/outcome/button-revert.png and /dev/null differ diff --git a/out/assets/images/battle/outcome/dialog.png b/out/assets/images/battle/outcome/dialog.png deleted file mode 100644 index 863c644..0000000 Binary files a/out/assets/images/battle/outcome/dialog.png and /dev/null differ diff --git a/out/assets/images/common/dialog-textbutton.png b/out/assets/images/common/dialog-textbutton.png new file mode 100644 index 0000000..8d69f86 Binary files /dev/null and b/out/assets/images/common/dialog-textbutton.png differ diff --git a/package.json b/package.json index 415621f..001ff0e 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "shell": "${SHELL} || true", "postinstall": "rm -rf out/vendor && mkdir -p out/vendor && cp -r node_modules/phaser/build out/vendor/phaser && cp -r node_modules/phaser-plugin-scene-graph/dist out/vendor/phaser-plugin-scene-graph && cp -r node_modules/parse/dist out/vendor/parse && cp -r node_modules/jasmine-core/lib/jasmine-core out/vendor/jasmine", "build": "tsc -p .", - "pack": "rm -f out/assets/atlas* && find graphics/exported -name '*.png' -print0 | xargs -0 gf-pack --name out/assets/atlas --fullpath --width 1024 --height 1024 --square --powerOfTwo --trim --padding 2", + "atlas": "rm -f out/assets/atlas* && find graphics/exported -name '*.png' -print0 | xargs -0 gf-pack --name out/assets/atlas --fullpath --width 1024 --height 1024 --square --powerOfTwo --trim --padding 2", "pretest": "tsc -p .", "test": "karma start spec/support/karma.conf.js && remap-istanbul -i out/coverage/coverage.json -o out/coverage -t html", "prestart": "tsc -p . || true", @@ -41,4 +41,4 @@ "phaser": "^2.6.2", "phaser-plugin-scene-graph": "^1.0.4" } -} +} \ No newline at end of file diff --git a/src/ui/Preload.ts b/src/ui/Preload.ts index f78f505..b9b5a31 100644 --- a/src/ui/Preload.ts +++ b/src/ui/Preload.ts @@ -19,6 +19,7 @@ module TS.SpaceTac.UI { this.loadImage("common/button-ok.png"); this.loadImage("common/button-cancel.png"); this.loadImage("common/dialog.png"); + this.loadSheet("common/dialog-textbutton.png", 316, 59); this.loadSheet("common/dialog-close.png", 92, 82); this.loadImage("menu/title.png"); this.loadImage("menu/button.png"); @@ -51,13 +52,6 @@ module TS.SpaceTac.UI { this.loadImage("battle/weapon/hot.png"); this.loadImage("battle/weapon/shield-impact.png"); this.loadImage("battle/weapon/blast.png"); - this.loadImage("battle/outcome/dialog.png"); - this.loadImage("battle/outcome/title-victory.png"); - this.loadImage("battle/outcome/title-defeat.png"); - this.loadImage("battle/outcome/button-menu.png"); - this.loadImage("battle/outcome/button-map.png"); - this.loadImage("battle/outcome/button-revert.png"); - this.loadImage("battle/outcome/button-loot.png"); this.loadImage("map/starsystem-background.png"); this.loadImage("map/current-location.png"); this.loadImage("map/name.png"); diff --git a/src/ui/battle/BattleView.ts b/src/ui/battle/BattleView.ts index 3894a3a..bb52527 100644 --- a/src/ui/battle/BattleView.ts +++ b/src/ui/battle/BattleView.ts @@ -41,9 +41,6 @@ module TS.SpaceTac.UI { // Ship tooltip ship_tooltip: ShipTooltip - // Outcome dialog layer - outcome_layer: Phaser.Group - // Character sheet character_sheet: CharacterSheet @@ -101,8 +98,6 @@ module TS.SpaceTac.UI { this.action_bar = new ActionBar(this); this.ship_list = new ShipList(this); this.ship_tooltip = new ShipTooltip(this); - this.outcome_layer = new Phaser.Group(this.game); - this.layer_dialogs.add(this.outcome_layer); this.character_sheet = new CharacterSheet(this, -this.getWidth()); this.layer_sheets.add(this.character_sheet); @@ -250,8 +245,7 @@ module TS.SpaceTac.UI { this.battle.stats.processLog(this.battle.log, this.player.fleet); - let dialog = new OutcomeDialog(this, this.player, this.battle.outcome, this.battle.stats); - dialog.moveToLayer(this.outcome_layer); + new OutcomeDialog(this, this.player, this.battle.outcome, this.battle.stats); } else { console.error("Battle not ended !"); } diff --git a/src/ui/battle/OutcomeDialog.ts b/src/ui/battle/OutcomeDialog.ts index 815f1a4..09c99a1 100644 --- a/src/ui/battle/OutcomeDialog.ts +++ b/src/ui/battle/OutcomeDialog.ts @@ -1,45 +1,87 @@ -/// +/// module TS.SpaceTac.UI { /** * Dialog to display battle outcome */ - export class OutcomeDialog extends UIComponent { + export class OutcomeDialog extends UIDialog { + battleview: BattleView + player: Player + outcome: BattleOutcome + stats: BattleStats + constructor(parent: BattleView, player: Player, outcome: BattleOutcome, stats: BattleStats) { - super(parent, 1428, 1032, "battle-outcome-dialog"); + super(parent); - let victory = outcome.winner && (outcome.winner.player == player); - this.addImage(714, 164, victory ? "battle-outcome-title-victory" : "battle-outcome-title-defeat"); + this.battleview = parent; + this.player = player; + this.outcome = outcome; + this.stats = stats; - if (victory) { - this.addButton(502, 871, () => { - parent.character_sheet.show(nn(outcome.winner).ships[0]); - parent.character_sheet.setLoot(outcome.loot); - }, "battle-outcome-button-loot", 0, 0, "Open character sheet to loot equipment from defeated fleet"); + this.refreshContent(); + } - this.addButton(924, 871, () => { - parent.exitBattle(); - }, "battle-outcome-button-map", 0, 0, "Exit the battle and go back to the map"); - } else { - this.addButton(502, 871, () => { - parent.revertBattle(); - }, "battle-outcome-button-revert", 0, 0, "Go back to where the fleet was before the battle happened"); + /** + * Shortcut to add a single action button at the bottom of dialog + */ + addActionButton(x: number, text: string, tooltip: string, action: Function) { + let button = this.addButton(x, 885, action, "common-dialog-textbutton", 0, 1, tooltip); + button.addChild(this.addText(0, 0, text, "#d9e0e5")); + } - this.addButton(924, 871, () => { - // Quit the game, and go back to menu - parent.gameui.quitGame(); - }, "battle-outcome-button-menu", 0, 0, "Quit the game, and go back to main menu"); - } + /** + * Refresh the whole dialog + */ + refreshContent(): void { + let parent = this.battleview; + let outcome = this.outcome; + let victory = outcome.winner && (outcome.winner.player == this.player); - this.addText(780, 270, "You", "#ffffff", 20); - this.addText(980, 270, "Enemy", "#ffffff", 20); - stats.getImportant(10).forEach((stat, index) => { - this.addText(500, 314 + 40 * index, stat.name, "#ffffff", 20); - this.addText(780, 314 + 40 * index, stat.attacker.toString(), "#8ba883", 20, true); - this.addText(980, 314 + 40 * index, stat.defender.toString(), "#cd6767", 20, true); + this.clearContent(); + + this.addImage(747, 180, victory ? "battle-outcome-title-victory" : "battle-outcome-title-defeat"); + + this.addText(815, 320, "You", "#ffffff", 20); + this.addText(1015, 320, "Enemy", "#ffffff", 20); + this.stats.getImportant(10).forEach((stat, index) => { + this.addText(530, 364 + 40 * index, stat.name, "#ffffff", 20); + this.addText(815, 364 + 40 * index, stat.attacker.toString(), "#8ba883", 20, true); + this.addText(1015, 364 + 40 * index, stat.defender.toString(), "#cd6767", 20, true); }); - this.setPositionInsideParent(0.5, 0.5); + if (!this.battleview.session.hasUniverse()) { + this.addActionButton(747, "Main menu", "Exit the battle and go back to the main menu", () => { + parent.exitBattle(); + }); + } else if (victory) { + if (this.outcome.loot.length) { + this.addActionButton(535, "Loot equipment", "Open character sheet to loot equipment from defeated fleet", () => { + let sheet = new CharacterSheet(this.view, undefined, undefined, () => { + sheet.destroy(true); + this.refreshContent(); + }); + sheet.show(this.player.fleet.ships[0], false); + sheet.setLoot(outcome.loot); + this.view.add.existing(sheet); + }); + + this.addActionButton(957, "Back to map", "Exit the battle and go back to the map", () => { + parent.exitBattle(); + }); + } else { + this.addActionButton(747, "Back to map", "Exit the battle and go back to the map", () => { + parent.exitBattle(); + }); + } + } else { + this.addActionButton(535, "Revert battle", "Go back to where the fleet was before the battle happened", () => { + parent.revertBattle(); + }); + + this.addActionButton(957, "Main menu", "Quit the game, and go back to main menu", () => { + parent.gameui.quitGame(); + }); + } } } } diff --git a/src/ui/character/CharacterSheet.ts b/src/ui/character/CharacterSheet.ts index 9c3d92f..70a7559 100644 --- a/src/ui/character/CharacterSheet.ts +++ b/src/ui/character/CharacterSheet.ts @@ -63,7 +63,7 @@ module TS.SpaceTac.UI { // Attributes and skills attributes: { [key: string]: Phaser.Text } = {}; - constructor(view: BaseView, xhidden = -2000, xshown = 0) { + constructor(view: BaseView, xhidden = -2000, xshown = 0, onclose?: Function) { super(view.game, 0, 0, "character-sheet"); this.view = view; @@ -73,7 +73,10 @@ module TS.SpaceTac.UI { this.xhidden = xhidden; this.inputEnabled = true; - let close_button = new Phaser.Button(this.game, view.getWidth(), 0, "character-close", () => this.hide()); + if (!onclose) { + onclose = () => this.hide(); + } + let close_button = new Phaser.Button(this.game, view.getWidth(), 0, "character-close", onclose); close_button.anchor.set(1, 0); UIComponent.setButtonSound(close_button); this.addChild(close_button); @@ -283,7 +286,7 @@ module TS.SpaceTac.UI { } if (animate) { - this.game.tweens.create(this).to({ x: this.xshown }, 800, Phaser.Easing.Circular.InOut, true); + this.game.tweens.create(this).to({ x: this.xshown }, 400, Phaser.Easing.Circular.InOut, true); } else { this.x = this.xshown; } @@ -304,7 +307,7 @@ module TS.SpaceTac.UI { this.view.audio.playOnce("ui-dialog-close"); if (animate) { - this.game.tweens.create(this).to({ x: this.xhidden }, 800, Phaser.Easing.Circular.InOut, true); + this.game.tweens.create(this).to({ x: this.xhidden }, 400, Phaser.Easing.Circular.InOut, true); } else { this.x = this.xhidden; } diff --git a/src/ui/common/UIComponent.ts b/src/ui/common/UIComponent.ts index b90d10b..ee6b61b 100644 --- a/src/ui/common/UIComponent.ts +++ b/src/ui/common/UIComponent.ts @@ -212,21 +212,21 @@ module TS.SpaceTac.UI { /** * Add a button in the component, positioning its center. */ - addButton(x: number, y: number, on_click: Function, background: string, frame_normal = 0, frame_hover = 1, tooltip = "", angle = 0) { + addButton(x: number, y: number, on_click: Function, background: string, frame_normal = 0, frame_hover = 1, tooltip = ""): Phaser.Button { let button = new Phaser.Button(this.view.game, x, y, background, on_click, undefined, frame_hover, frame_normal); UIComponent.setButtonSound(button); button.anchor.set(0.5, 0.5); - button.angle = angle; if (tooltip) { this.view.tooltip.bindStaticText(button, tooltip); } this.addInternalChild(button); + return button; } /** * Add a static text. */ - addText(x: number, y: number, content: string, color = "#ffffff", size = 16, bold = false, center = true, width = 0, vcenter = center): void { + addText(x: number, y: number, content: string, color = "#ffffff", size = 16, bold = false, center = true, width = 0, vcenter = center): Phaser.Text { let style = { font: `${bold ? "bold " : ""}${size}pt SpaceTac`, fill: color, align: center ? "center" : "left" }; let text = new Phaser.Text(this.view.game, x, y, content, style); text.anchor.set(center ? 0.5 : 0, vcenter ? 0.5 : 0); @@ -235,12 +235,15 @@ module TS.SpaceTac.UI { text.wordWrapWidth = width; } this.addInternalChild(text); + return text; } /** * Add a static image, positioning its center. + * + * DEPRECATED - Use addImage instead */ - addImage(x: number, y: number, key: string, frame = 0, scale = 1): void { + addImageF(x: number, y: number, key: string, frame = 0, scale = 1): void { let image = new Phaser.Image(this.container.game, x, y, key, frame); image.anchor.set(0.5, 0.5); image.scale.set(scale); @@ -250,12 +253,13 @@ module TS.SpaceTac.UI { /** * Add a static image, from atlases, positioning its center. */ - addImageA(x: number, y: number, name: string, scale = 1): void { + addImage(x: number, y: number, name: string, scale = 1): Phaser.Image { let info = this.view.getImageInfo(name); let image = new Phaser.Image(this.container.game, x, y, info.key, info.frame); image.anchor.set(0.5, 0.5); image.scale.set(scale); this.addInternalChild(image); + return image; } /** diff --git a/src/ui/common/UIDialog.ts b/src/ui/common/UIDialog.ts index 998e0d9..c68085f 100644 --- a/src/ui/common/UIDialog.ts +++ b/src/ui/common/UIDialog.ts @@ -24,7 +24,8 @@ module TS.SpaceTac.UI { * Add a control-capturing overlay */ addOverlay(layer: Phaser.Group): void { - let overlay = layer.game.add.button(0, 0, "common-transparent", () => null); + let info = this.view.getImageInfo("translucent"); + let overlay = layer.game.add.button(0, 0, info.key, () => null, undefined, info.frame, info.frame); overlay.input.useHandCursor = false; overlay.scale.set(this.view.getWidth() / overlay.width, this.view.getHeight() / overlay.height); layer.add(overlay); diff --git a/src/ui/common/UIWaitingDialog.ts b/src/ui/common/UIWaitingDialog.ts index 4326333..8d0c4b3 100644 --- a/src/ui/common/UIWaitingDialog.ts +++ b/src/ui/common/UIWaitingDialog.ts @@ -7,7 +7,7 @@ module TS.SpaceTac.UI { super(view); this.addText(this.width * 0.5, this.height * 0.3, message, "#90FEE3", 32); - this.addImage(this.width * 0.5, this.height * 0.6, "common-waiting"); + this.addImageF(this.width * 0.5, this.height * 0.6, "common-waiting"); } /** diff --git a/src/ui/intro/ProgressiveMessage.ts b/src/ui/intro/ProgressiveMessage.ts index 63ce9e2..410e0e3 100644 --- a/src/ui/intro/ProgressiveMessage.ts +++ b/src/ui/intro/ProgressiveMessage.ts @@ -43,7 +43,7 @@ module TS.SpaceTac.UI { width -= offset; let ioffset = style.padding + Math.floor(style.image_size / 2); - this.addImageA(ioffset, ioffset, style.image); + this.addImage(ioffset, ioffset, style.image); if (style.image_caption) { let text_size = Math.ceil(style.text_size * 0.6); diff --git a/src/ui/map/ActiveMissionsDisplay.ts b/src/ui/map/ActiveMissionsDisplay.ts index cf1bc0b..5739557 100644 --- a/src/ui/map/ActiveMissionsDisplay.ts +++ b/src/ui/map/ActiveMissionsDisplay.ts @@ -47,7 +47,7 @@ module TS.SpaceTac.UI { let offset = 245 - active.length * spacing; active.forEach((mission, idx) => { let frame = mission.main ? 0 : 1; - this.addImage(35, offset + spacing * idx, "map-missions", frame); + this.addImageF(35, offset + spacing * idx, "map-missions", frame); this.addText(90, offset + spacing * idx, mission.current_part.title, "#d2e1f3", 20, false, false, 430, true); let location = mission.current_part.getLocationHint(); diff --git a/src/ui/map/MapLocationMenu.ts b/src/ui/map/MapLocationMenu.ts index 6c720e9..6693292 100644 --- a/src/ui/map/MapLocationMenu.ts +++ b/src/ui/map/MapLocationMenu.ts @@ -16,7 +16,7 @@ module TS.SpaceTac.UI { this.clearContent(); if (title) { - this.addImage(239, 57, "map-subname"); + this.addImageF(239, 57, "map-subname"); this.addText(239, 57, title, "#b8d2f1", 22, false, true); } diff --git a/src/ui/map/MissionsDialog.ts b/src/ui/map/MissionsDialog.ts index b6783d9..805fc99 100644 --- a/src/ui/map/MissionsDialog.ts +++ b/src/ui/map/MissionsDialog.ts @@ -62,7 +62,7 @@ module TS.SpaceTac.UI { let title = mission.title; let subtitle = `${capitalize(MissionDifficulty[mission.difficulty])} - Reward: ${mission.getRewardText()}`; - this.addImage(320, yoffset, "map-missions", 1); + this.addImageF(320, yoffset, "map-missions", 1); if (title) { this.addText(380, yoffset - 15, title, "#d2e1f3", 22, false, false, 620, true); } diff --git a/src/ui/menu/LoadDialog.ts b/src/ui/menu/LoadDialog.ts index fd53608..5663855 100644 --- a/src/ui/menu/LoadDialog.ts +++ b/src/ui/menu/LoadDialog.ts @@ -13,8 +13,9 @@ module TS.SpaceTac.UI { constructor(parent: MainMenu) { super(parent, 1344, 566, "menu-load-bg"); - this.addButton(600, 115, () => this.paginateSave(-1), "common-arrow", 0, 0, "Scroll to newer saves", 180); - this.addButton(1038, 115, () => this.paginateSave(1), "common-arrow", 0, 0, "Scroll to older saves", 0); + let button = this.addButton(600, 115, () => this.paginateSave(-1), "common-arrow", 0, 0, "Scroll to newer saves"); + button.angle = 180; + this.addButton(1038, 115, () => this.paginateSave(1), "common-arrow", 0, 0, "Scroll to older saves"); this.addButton(1224, 115, () => this.load(), "common-button-ok"); this.addButton(1224, 341, () => this.join(), "common-button-ok");