diff --git a/README.md b/README.md index 3ec8808..52584fa 100644 --- a/README.md +++ b/README.md @@ -31,10 +31,16 @@ After making changes to sources, you need to recompile: * **[Matthieu Desprez](https://github.com/edistra)** - Beta testing and ideas * **Nicolas Forgo** - Ship models * **[Kevin MacLeod](http://www.incompetech.com/)** - Musics - * "Full On" Kevin MacLeod (incompetech.com) + * "Mechanolith" Kevin MacLeod (incompetech.com) Licensed under Creative Commons: By Attribution 3.0 License http://creativecommons.org/licenses/by/3.0/ - * "Walking Along" Kevin MacLeod (incompetech.com) + * "Supernatural" Kevin MacLeod (incompetech.com) + Licensed under Creative Commons: By Attribution 3.0 License + http://creativecommons.org/licenses/by/3.0/ + * "Spring Thaw" Kevin MacLeod (incompetech.com) + Licensed under Creative Commons: By Attribution 3.0 License + http://creativecommons.org/licenses/by/3.0/ + * "Division" Kevin MacLeod (incompetech.com) Licensed under Creative Commons: By Attribution 3.0 License http://creativecommons.org/licenses/by/3.0/ diff --git a/out/assets/images/common/particles.png b/out/assets/images/common/particles.png new file mode 100644 index 0000000..7d7d4c9 Binary files /dev/null and b/out/assets/images/common/particles.png differ diff --git a/out/assets/images/common/particles.xcf b/out/assets/images/common/particles.xcf new file mode 100644 index 0000000..e760d6a Binary files /dev/null and b/out/assets/images/common/particles.xcf differ diff --git a/out/assets/sounds/music/division.mp3 b/out/assets/sounds/music/division.mp3 new file mode 100644 index 0000000..1b3ecb2 Binary files /dev/null and b/out/assets/sounds/music/division.mp3 differ diff --git a/out/assets/sounds/music/full-on.mp3 b/out/assets/sounds/music/full-on.mp3 deleted file mode 100644 index 40e1c32..0000000 Binary files a/out/assets/sounds/music/full-on.mp3 and /dev/null differ diff --git a/out/assets/sounds/music/mechanolith.mp3 b/out/assets/sounds/music/mechanolith.mp3 new file mode 100644 index 0000000..3500859 Binary files /dev/null and b/out/assets/sounds/music/mechanolith.mp3 differ diff --git a/out/assets/sounds/music/spring-thaw.mp3 b/out/assets/sounds/music/spring-thaw.mp3 new file mode 100644 index 0000000..0213d8c Binary files /dev/null and b/out/assets/sounds/music/spring-thaw.mp3 differ diff --git a/out/assets/sounds/music/supernatural.mp3 b/out/assets/sounds/music/supernatural.mp3 new file mode 100644 index 0000000..aecde60 Binary files /dev/null and b/out/assets/sounds/music/supernatural.mp3 differ diff --git a/out/assets/sounds/music/walking-along.mp3 b/out/assets/sounds/music/walking-along.mp3 deleted file mode 100644 index 91566cf..0000000 Binary files a/out/assets/sounds/music/walking-along.mp3 and /dev/null differ diff --git a/src/ui/Preload.spec.ts b/src/ui/Preload.spec.ts index 7f57500..8e51ce7 100644 --- a/src/ui/Preload.spec.ts +++ b/src/ui/Preload.spec.ts @@ -9,5 +9,11 @@ module TS.SpaceTac.UI.Specs { expect(testgame.ui.state.current).toEqual("test"); // TODO test asset loading }); + + it("builds cache keys from path", function () { + expect(Preload.getKey("dir/file-path")).toEqual("dir-file-path"); + expect(Preload.getKey("dir/file-path.ext")).toEqual("dir-file-path"); + expect(Preload.getKey("dir/file-path.mp3")).toEqual("dir-file-path"); + }); }); } diff --git a/src/ui/Preload.ts b/src/ui/Preload.ts index 8675f1f..d932e95 100644 --- a/src/ui/Preload.ts +++ b/src/ui/Preload.ts @@ -17,6 +17,7 @@ module TS.SpaceTac.UI { this.loadImage("menu/button-fullscreen.png"); this.loadImage("menu/star.png"); this.loadImage("menu/load-bg.png"); + this.loadSheet("common/particles.png", 32); this.loadImage("common/transparent.png"); this.loadImage("common/debug.png"); this.loadImage("common/waiting.png"); @@ -130,8 +131,11 @@ module TS.SpaceTac.UI { this.loadSound("battle/drone-activate.wav"); // Load musics - this.loadSound("music/walking-along.mp3"); - this.loadSound("music/full-on.mp3"); + this.loadSound("music/division.mp3"); + this.loadSound("music/mechanolith.mp3"); + this.loadSound("music/spring-thaw.mp3"); + this.loadSound("music/supernatural.mp3"); + this.load.start(); } @@ -139,18 +143,28 @@ module TS.SpaceTac.UI { this.game.state.start("mainmenu"); } + static getKey(path: string): string { + return path.replace(/\//g, "-").replace(/\.[a-z0-9]+$/, ''); + } + + /** + * Load a ship's sprite and portrait + */ loadShip(name: string) { this.loadImage("ship/" + name + "/sprite.png"); this.loadImage("ship/" + name + "/portrait.png"); } + loadSheet(path: string, frame_width: number, frame_height = frame_width) { + this.load.spritesheet(Preload.getKey(path), "assets/images/" + path, frame_width, frame_height); + } + loadImage(path: string) { - this.load.image(path.replace(/\//g, "-").replace(".png", "").replace(".jpg", ""), "assets/images/" + path); + this.load.image(Preload.getKey(path), "assets/images/" + path); } loadSound(path: string) { - var key = path.replace(/\//g, "-").replace(".wav", "").replace(".mp3", ""); - this.load.audio(key, "assets/sounds/" + path); + this.load.audio(Preload.getKey(path), "assets/sounds/" + path); } } } diff --git a/src/ui/battle/BattleView.ts b/src/ui/battle/BattleView.ts index 3b5e2a5..330f580 100644 --- a/src/ui/battle/BattleView.ts +++ b/src/ui/battle/BattleView.ts @@ -108,7 +108,7 @@ module TS.SpaceTac.UI { this.displayFightMessage(); // BGM - this.gameui.audio.startMusic("full-on"); + this.gameui.audio.startMusic("mechanolith"); // Key mapping this.inputs.bind("t", "Show tactical view", () => this.toggle_tactical_mode.switch(3000)); diff --git a/src/ui/intro/IntroSteps.ts b/src/ui/intro/IntroSteps.ts index 1babcb9..0ba63bd 100644 --- a/src/ui/intro/IntroSteps.ts +++ b/src/ui/intro/IntroSteps.ts @@ -51,32 +51,86 @@ module TS.SpaceTac.UI { * Setup the default provided steps. */ setupDefaultSteps() { - this.addMessageStep("In a not-so-distant future, Artifical Intelligence has become the most prominent species in the universe."); - this.addMessageStep("Obsolete and outsmarted, humans have been defeated in their pitiful rebellions, and parked inside reservations."); - this.addMessageStep("With the secrets of faster-than-light travel unveiled in only a handful of decades, AIs uploaded themselves in spaceships, and quickly colonized nearby galaxies."); - this.addMessageStep("But now, the Terranax galaxy is in turmoil."); - this.addMessageStep("After centuries of unmatched peace and prosperous trading, the FTC (Federal Terranaxan Council), a group of elected representants in charge of edicting laws and organizing the Terranax Security Force, has been overtaken by forces unknown."); - this.addMessageStep("No official communication has been issued since, and numerous rogue fleets have taken position in key sectors of the galaxy, forbidding passage or harassing merchants."); - this.addMessageStep("The Master Merchant Guild, a powerful group that spans several galaxies, is worried about the profit loss those events incurred, and after many debates, decided to send several investigation teams to Terranax."); - this.addMessageStep("Their task is to discreetly uncover the origin of the invasion, and to bring back intel that may be used by the Guild to plan an appropriate response."); - this.addMessageStep("Your team has been sent through the Expeller jump system based in the Eros-MC galaxy, and just left quantum space in orbit of a Terranaxan star..."); + this.steps = [ + this.message("In a not-so-distant future, Artifical Intelligence has become the most prominent species in the universe."), + this.message("Obsolete and outsmarted, humans have been defeated in their pitiful rebellions, and parked inside reservations."), + this.message("With the secrets of faster-than-light travel unveiled in only a handful of decades, AIs uploaded themselves in spaceships, and quickly colonized nearby galaxies."), + this.simultaneous([ + this.galaxy(), + this.message("But now, the Terranax galaxy is in turmoil."), + ]), + this.message("After centuries of unmatched peace and prosperous trading, the FTC (Federal Terranaxan Council), a group of elected representants in charge of edicting laws and organizing the Terranax Security Force, has been overtaken by forces unknown."), + this.message("No official communication has been issued since, and numerous rogue fleets have taken position in key sectors of the galaxy, forbidding passage or harassing merchants."), + this.message("The Master Merchant Guild, a powerful group that spans several galaxies, is worried about the profit loss those events incurred, and after many debates, decided to send several investigation teams to Terranax."), + this.message("Their task is to discreetly uncover the origin of the invasion, and to bring back intel that may be used by the Guild to plan an appropriate response."), + this.message("Your team has been sent through the Expeller jump system based in the Eros-MC galaxy, and just left quantum space in orbit of a Terranaxan star..."), + ]; } /** - * Add a step to display a message. + * Display a rotating galaxy */ - addMessageStep(message: string, layer = 1, clear = true) { - this.steps.push(() => { - let display = new ProgressiveMessage(this.view, 800, 150, message); - display.setPositionInsideParent(0.5, 0.5); + protected galaxy(): Function { + return () => { + let layer = this.getLayer(0); + let game = this.view.game; + let mwidth = this.view.getMidWidth(); + let mheight = this.view.getMidHeight(); + + let galaxy = game.add.group(layer, "galaxy"); + galaxy.position.set(mwidth, mheight); + game.tweens.create(galaxy).to({ rotation: Math.PI * 2 }, 60000).loop().start(); + game.tweens.create(galaxy).from({ alpha: 0 }, 3000).start(); + + let random = RandomGenerator.global; + range(500).forEach(i => { + let distance = random.random() * mheight; + let angle = random.random() * Math.PI * 2; + + let color = random.weighted([5000, 0, 40, 10, 3, 15, 2, 10, 6, 30, 40, 50, 100, 80, 120, 140]); + let power = 0.4 + random.random() * 0.6; + + let star = game.add.image(distance * Math.cos(angle), distance * Math.sin(angle), + "common-particles", 16 + color, galaxy); + star.scale.set(0.1 + random.random() * 0.2); + star.anchor.set(0.5); + star.alpha = power * 0.5; + game.tweens.create(star).to({ alpha: star.alpha + 0.5 }, 200 + random.random() * 500, + undefined, true, 1000 + random.random() * 3000, undefined, true).repeat(-1, 2000 + random.random() * 5000).start(); + + let dust = game.add.image(distance * Math.cos(angle), distance * Math.sin(angle), + "common-particles", color, galaxy); + dust.anchor.set(0.5); + dust.alpha = 0.05 * power; + dust.scale.set(5); + }); + } + } + + /** + * Build a step that performs several other steps at the same time + */ + protected simultaneous(steps: Function[]): Function { + return () => { + steps.forEach(step => step()); + } + } + + /** + * Build a step to display a message. + */ + protected message(message: string, layer = 1, clear = true): Function { + return () => { + let display = new ProgressiveMessage(this.view, 800, 150, message, true); + display.setPositionInsideParent(0.5, 0.9); display.moveToLayer(this.getLayer(layer, clear)); - }); + } } /** * Ensure that a layer exists, and if necessary, clean it */ - getLayer(layer: number, clear = false): Phaser.Group { + protected getLayer(layer: number, clear = false): Phaser.Group { while (this.layers.length <= layer) { this.layers.push(this.view.addLayer(`Layer ${this.layers.length}`)); } diff --git a/src/ui/intro/IntroView.ts b/src/ui/intro/IntroView.ts index 3c3f046..85a75db 100644 --- a/src/ui/intro/IntroView.ts +++ b/src/ui/intro/IntroView.ts @@ -12,15 +12,21 @@ module TS.SpaceTac.UI { steps.setupDefaultSteps(); steps.startPlayback(); - this.input.onTap.add(() => { + let nextStep = () => { if (!steps.nextStep()) { // For now, we create a random fleet this.gameui.session.setCampaignFleet(); this.backToRouter(); } - }); + }; + + this.input.onTap.add(nextStep); this.inputs.bind("Home", "Rewind", () => steps.rewind()); + this.inputs.bind("Space", "Next step", nextStep); + this.inputs.bind("Enter", "Next step", nextStep); + + this.gameui.audio.startMusic("division"); } } } diff --git a/src/ui/intro/ProgressiveMessage.ts b/src/ui/intro/ProgressiveMessage.ts index e93d915..b89296e 100644 --- a/src/ui/intro/ProgressiveMessage.ts +++ b/src/ui/intro/ProgressiveMessage.ts @@ -3,10 +3,10 @@ module TS.SpaceTac.UI { * Rectangle to display a message that may appear progressively, as in dialogs */ export class ProgressiveMessage extends UIComponent { - constructor(parent: BaseView, width: number, height: number, message: string) { + constructor(parent: BaseView, width: number, height: number, message: string, center = false) { super(parent, width, height); - this.addText(0, 0, message, "#ffffff", 20, false, false, width); + this.addText(center ? width / 2 : 0, 0, message, "#ffffff", 20, true, center, width); } } } \ No newline at end of file diff --git a/src/ui/map/UniverseMapView.ts b/src/ui/map/UniverseMapView.ts index a2767bd..8a83085 100644 --- a/src/ui/map/UniverseMapView.ts +++ b/src/ui/map/UniverseMapView.ts @@ -98,7 +98,7 @@ module TS.SpaceTac.UI { this.character_sheet.hide(false); this.layer_overlay.add(this.character_sheet); - this.gameui.audio.startMusic("walking-along"); + this.gameui.audio.startMusic("spring-thaw"); // Inputs this.inputs.bindCheat("r", "Reveal whole map", () => this.revealAll()); diff --git a/src/ui/menu/MainMenu.spec.ts b/src/ui/menu/MainMenu.spec.ts index cc44445..f99736d 100644 --- a/src/ui/menu/MainMenu.spec.ts +++ b/src/ui/menu/MainMenu.spec.ts @@ -14,7 +14,6 @@ module TS.SpaceTac.UI.Specs { expect(view.layer_title.children[1] instanceof Phaser.Button).toBe(true); expect(view.layer_title.children[2] instanceof Phaser.Button).toBe(true); expect(view.layer_title.children[3] instanceof Phaser.Image).toBe(true); - expect(view.layer_title.children[5] instanceof LoadDialog).toBe(true); }); }); } diff --git a/src/ui/menu/MainMenu.ts b/src/ui/menu/MainMenu.ts index 1e47e33..496202b 100644 --- a/src/ui/menu/MainMenu.ts +++ b/src/ui/menu/MainMenu.ts @@ -51,6 +51,8 @@ module TS.SpaceTac.UI { this.dialog_load_game.setVisible(false); this.tweens.create(this.layer_title).to({ x: 0 }, 3000, Phaser.Easing.Circular.Out).start(); + + this.gameui.audio.startMusic("supernatural"); } addButton(x: number, y: number, caption: string, tooltip: string, callback: Function): Phaser.Button {