diff --git a/graphics/ui/map.svg b/graphics/ui/map.svg index 3586ea9..3d45445 100644 --- a/graphics/ui/map.svg +++ b/graphics/ui/map.svg @@ -811,8 +811,8 @@ style="color-interpolation-filters:sRGB" inkscape:label="Drop Shadow" id="filter7229-3" - x="-0.2" - y="-0.2" + x="-0.25" + y="-0.25" height="1.5" width="1.5"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + inkscape:snap-global="false" + inkscape:snap-object-midpoints="true" + inkscape:measure-start="551.543,453.963" + inkscape:measure-end="1261.48,449.72"> + + + + + + X + + Active jobs + Proposed jobs + + + + Escort a merchant transport to Rhinard + Reward : 500 zotys + + + + + + Deliver an item to the FTC contact in Suburbia + Reward : Legendary SubMunition Missile Mk4 + + + Cannot accept more missions + + + + + + Cancel + + + + + + + Deliver an item to the FTC contact in Suburbia + Reward : Legendary SubMunition Missile Mk4 + + + + + + Deliver an item to the FTC contact in Suburbia + Reward : Legendary SubMunition Missile Mk4 + + + + + + Deliver an item to the FTC contact in Suburbia + Reward : Legendary SubMunition Missile Mk4 + + + + Accept + + + + + + + + + + diff --git a/out/assets/images/common/dialog.png b/out/assets/images/common/dialog.png new file mode 100644 index 0000000..8a66288 Binary files /dev/null and b/out/assets/images/common/dialog.png differ diff --git a/out/assets/images/map/mission-action.png b/out/assets/images/map/mission-action.png new file mode 100644 index 0000000..a4ede33 Binary files /dev/null and b/out/assets/images/map/mission-action.png differ diff --git a/src/core/NameGenerator.ts b/src/core/NameGenerator.ts index f2c6ba8..36d93c2 100644 --- a/src/core/NameGenerator.ts +++ b/src/core/NameGenerator.ts @@ -8,7 +8,7 @@ module TS.SpaceTac { private random: RandomGenerator; constructor(choices: string[], random: RandomGenerator = new RandomGenerator()) { - this.choices = choices.slice(0); + this.choices = acopy(choices); this.random = random; } diff --git a/src/core/Shop.spec.ts b/src/core/Shop.spec.ts index ea86cbd..1dda8a6 100644 --- a/src/core/Shop.spec.ts +++ b/src/core/Shop.spec.ts @@ -31,5 +31,41 @@ module TS.SpaceTac.Specs { expect(shop.stock).toEqual([equ1, equ2]); expect(fleet.credits).toEqual(1000); }); + + it("generates secondary missions", function () { + let universe = new Universe(); + universe.generate(4); + let start = universe.getStartLocation(); + + let shop = new Shop(); + expect((shop).missions.length).toBe(0); + + let result = shop.getMissions(start, 4); + expect(result.length).toBe(4); + expect((shop).missions.length).toBe(4); + + let oresult = shop.getMissions(start, 4); + expect(oresult).toEqual(result); + + result.forEach(mission => { + expect(mission.main).toBe(false); + }); + }); + + it("assigns missions to a fleet", function () { + let shop = new Shop(); + let player = new Player(); + let mission = new Mission(new Universe()); + (shop).missions = [mission]; + + expect(shop.getMissions(new StarLocation(), 1)).toEqual([mission]); + expect(player.missions.secondary).toEqual([]); + + shop.acceptMission(mission, player); + + expect((shop).missions).toEqual([]); + expect(player.missions.secondary).toEqual([mission]); + expect(mission.fleet).toBe(player.fleet); + }); }); } diff --git a/src/core/Shop.ts b/src/core/Shop.ts index a0c71a3..5f94786 100644 --- a/src/core/Shop.ts +++ b/src/core/Shop.ts @@ -15,6 +15,9 @@ module TS.SpaceTac { // Random generator private random: RandomGenerator + // Available missions + private missions: Mission[] = [] + constructor(level = 1, stock: Equipment[] = [], count = 40) { this.level = level; this.stock = stock; @@ -98,5 +101,33 @@ module TS.SpaceTac { return false; } } + + /** + * Get a list of available secondary missions + */ + getMissions(around: StarLocation, max_count = 3): Mission[] { + while (this.missions.length < max_count) { + let generator = new MissionGenerator(around.star.universe, around.star.level, around, this.random); + let mission = generator.generate(); + this.missions.push(mission); + } + + return this.missions; + } + + /** + * Assign a mission to a fleet + * + * Returns true on success + */ + acceptMission(mission: Mission, player: Player): boolean { + if (player.missions.secondary.length < 2 && remove(this.missions, mission)) { + mission.fleet = player.fleet; + add(player.missions.secondary, mission); + return true; + } else { + return false; + } + } } } \ No newline at end of file diff --git a/src/core/Star.spec.ts b/src/core/Star.spec.ts index d8129cf..9784efa 100644 --- a/src/core/Star.spec.ts +++ b/src/core/Star.spec.ts @@ -2,10 +2,10 @@ module TS.SpaceTac.Specs { describe("Star", () => { it("lists links to other stars", () => { var universe = new Universe(); - universe.stars.push(new Star(universe, 0, 0)); - universe.stars.push(new Star(universe, 1, 0)); - universe.stars.push(new Star(universe, 0, 1)); - universe.stars.push(new Star(universe, 1, 1)); + universe.stars.push(new Star(universe, 0, 0, "Star A")); + universe.stars.push(new Star(universe, 1, 0, "Star B")); + universe.stars.push(new Star(universe, 0, 1, "Star C")); + universe.stars.push(new Star(universe, 1, 1, "Star D")); universe.addLink(universe.stars[0], universe.stars[1]); universe.addLink(universe.stars[0], universe.stars[3]); @@ -26,6 +26,11 @@ module TS.SpaceTac.Specs { expect(universe.stars[3].getLinkTo(universe.stars[0])).toEqual(universe.starlinks[1]); expect(universe.stars[3].getLinkTo(universe.stars[1])).toBeNull(); expect(universe.stars[3].getLinkTo(universe.stars[2])).toBeNull(); + + let neighbors = universe.stars[0].getNeighbors(); + expect(neighbors.length).toBe(2); + expect(neighbors).toContain(universe.stars[1]); + expect(neighbors).toContain(universe.stars[3]); }); }); } diff --git a/src/core/Star.ts b/src/core/Star.ts index 3aa2d43..bade1ef 100644 --- a/src/core/Star.ts +++ b/src/core/Star.ts @@ -89,6 +89,14 @@ module TS.SpaceTac { return `Star ${this.name}`; } + /** + * Add a location of interest + */ + addLocation(type: StarLocationType): StarLocation { + let result = new StarLocation(this, type); + return result; + } + // Get the distance to another star getDistanceTo(star: Star): number { var dx = this.x - star.x; @@ -159,6 +167,13 @@ module TS.SpaceTac { return result; } + /** + * Get the neighboring star systems (single jump accessible) + */ + getNeighbors(): Star[] { + return nna(this.getLinks().map(link => link.getPeer(this))); + } + // Check if a location is far enough from all other ones private checkMinDistance(loc: StarLocation, others: StarLocation[]): boolean { return others.every((iloc: StarLocation): boolean => { diff --git a/src/core/Universe.ts b/src/core/Universe.ts index 5cbb731..5257d5d 100644 --- a/src/core/Universe.ts +++ b/src/core/Universe.ts @@ -13,10 +13,31 @@ module TS.SpaceTac { radius = 5 // Source of randomness - random = RandomGenerator.global; + random = RandomGenerator.global - // Generates a universe, with star systems and such + /** + * Add a single star + */ + addStar(level = 1, name?: string): Star { + let result = new Star(this, 0, 0, name || `Star ${this.stars.length + 1}`); + result.level = level; + this.stars.push(result); + return result; + } + + /** + * Generates a random universe, with star systems and locations of interest + * + * This will also : + * - create a network of jump links between star systems + * - add random shops + * - define a progressive gradient of enemy levels + */ generate(starcount = 50): void { + if (starcount < 4) { + starcount = 4; + } + while (this.stars.length == 0 || any(this.stars, star => star.getLinks().length == 0)) { this.stars = this.generateStars(starcount); @@ -27,7 +48,7 @@ module TS.SpaceTac { this.generateWarpLocations(); this.stars.forEach((star: Star) => { - star.generate(); + star.generate(this.random); }); this.setEncounterLevels(); diff --git a/src/core/missions/MainStory.spec.ts b/src/core/missions/MainStory.spec.ts index 987dffb..754f53a 100644 --- a/src/core/missions/MainStory.spec.ts +++ b/src/core/missions/MainStory.spec.ts @@ -30,13 +30,13 @@ module TS.SpaceTac.Specs { let fleet_size = fleet.ships.length; checkPart(story, 0, "^Travel to Terranax galaxy$"); - (story.current_part).skip(); + (story.current_part).skip(); checkPart(story, 1, "^Find your contact in .*$"); goTo(fleet, (story.current_part).destination); checkPart(story, 2, "^Speak with your contact"); - (story.current_part).skip(); + (story.current_part).skip(); checkPart(story, 3, "^Go with .* in .* system$"); expect(fleet.ships.length).toBe(fleet_size + 1); diff --git a/src/core/missions/MainStory.ts b/src/core/missions/MainStory.ts index 12051f0..1fa440d 100644 --- a/src/core/missions/MainStory.ts +++ b/src/core/missions/MainStory.ts @@ -17,27 +17,27 @@ module TS.SpaceTac { let start_location = nn(fleet.location); // Arrival - let dialog = this.addPart(new MissionPartDialog(this, [], "Travel to Terranax galaxy")); - dialog.addPiece(null, "Wow ! From what my sensors tell me, there is not much activity around here."); - dialog.addPiece(null, "I remember the last time I came in this galaxy, you needed to be aware of collisions at all time, so crowded it was."); - dialog.addPiece(null, "Well...I did not pick a signal from our contact yet. We should be looking for her in this system."); + let conversation = this.addPart(new MissionPartConversation(this, [], "Travel to Terranax galaxy")); + conversation.addPiece(null, "Wow ! From what my sensors tell me, there is not much activity around here."); + conversation.addPiece(null, "I remember the last time I came in this galaxy, you needed to be aware of collisions at all time, so crowded it was."); + conversation.addPiece(null, "Well...I did not pick a signal from our contact yet. We should be looking for her in this system."); // Get in touch with our contact let contact_location = randomLocation(random, [start_location.star], [start_location]); let contact_character = new Ship(null, "Osten-37", ShipModel.getRandomModel(1, random)); contact_character.fleet.setLocation(contact_location, true); this.addPart(new MissionPartGoTo(this, contact_location, `Find your contact in ${contact_location.star.name}`)); - dialog = this.addPart(new MissionPartDialog(this, [contact_character], "Speak with your contact")); - dialog.addPiece(contact_character, "Finally, you came!"); - dialog.addPiece(contact_character, "Sorry for not broadcasting my position. As you may have encountered, this star system is not safe anymore."); - dialog.addPiece(null, "Nothing we could not handle, we just hope the other teams have not run across more trouble."); - dialog.addPiece(contact_character, "I do not even know if the other contacts made it to their rendezvous point. Jumping between systems has become quite a hassle around here."); - dialog.addPiece(null, "And we still do not know why those rogue fleets are trying to lockdown the whole galaxy? Did you have some interaction with them?"); - dialog.addPiece(contact_character, "Well, they tend to shoot you on sight if you go near a location they defend. Do not know if that qualifies as interaction though..."); - dialog.addPiece(null, "So where do we go from here? In your last message, you told us of a resistance group growing."); - dialog.addPiece(contact_character, "Yes, some merchants and miners have rallied behind a retired TSF general, but I lost contact with them weeks ago."); - dialog.addPiece(contact_character, "We may go to their last known location, but first I want you to see something in a nearby system."); - dialog.addPiece(null, "Ok, let's go..."); + conversation = this.addPart(new MissionPartConversation(this, [contact_character], "Speak with your contact")); + conversation.addPiece(contact_character, "Finally, you came!"); + conversation.addPiece(contact_character, "Sorry for not broadcasting my position. As you may have encountered, this star system is not safe anymore."); + conversation.addPiece(null, "Nothing we could not handle, we just hope the other teams have not run across more trouble."); + conversation.addPiece(contact_character, "I do not even know if the other contacts made it to their rendezvous point. Jumping between systems has become quite a hassle around here."); + conversation.addPiece(null, "And we still do not know why those rogue fleets are trying to lockdown the whole galaxy? Did you have some interaction with them?"); + conversation.addPiece(contact_character, "Well, they tend to shoot you on sight if you go near a location they defend. Do not know if that qualifies as interaction though..."); + conversation.addPiece(null, "So where do we go from here? In your last message, you told us of a resistance group growing."); + conversation.addPiece(contact_character, "Yes, some merchants and miners have rallied behind a retired TSF general, but I lost contact with them weeks ago."); + conversation.addPiece(contact_character, "We may go to their last known location, but first I want you to see something in a nearby system."); + conversation.addPiece(null, "Ok, let's go..."); // Go take a look at the graveyard let nearby_systems = nna(start_location.star.getLinks().map(link => link.getPeer(contact_location.star))); diff --git a/src/core/missions/Mission.ts b/src/core/missions/Mission.ts index 734c83c..d354b3d 100644 --- a/src/core/missions/Mission.ts +++ b/src/core/missions/Mission.ts @@ -21,13 +21,17 @@ module TS.SpaceTac { // Indicator that the mission is completed completed: boolean - constructor(universe: Universe, fleet: Fleet, main = false) { + // Title of this mission (should be kept short) + title: string + + constructor(universe: Universe, fleet = new Fleet(), main = false) { this.universe = universe; this.fleet = fleet; this.main = main; this.parts = []; this.completed = false; this.current_part = new MissionPart(this, "Empty mission"); + this.title = main ? "Main story" : "Secondary mission"; } /** diff --git a/src/core/missions/MissionGenerator.spec.ts b/src/core/missions/MissionGenerator.spec.ts new file mode 100644 index 0000000..25fc52c --- /dev/null +++ b/src/core/missions/MissionGenerator.spec.ts @@ -0,0 +1,24 @@ +module TS.SpaceTac.Specs { + describe("MissionGenerator", () => { + it("generates escort missions", () => { + let universe = new Universe(); + let star1 = universe.addStar(1); + let loc1 = star1.locations[0]; + let star2 = universe.addStar(2); + let loc2 = star2.locations[0]; + let star3 = universe.addStar(3); + let loc3 = star3.locations[0]; + universe.addLink(star1, star2); + universe.addLink(star2, star3); + + let generator = new MissionGenerator(universe, 3, loc2); + let mission = generator.generateEscort(); + + expect(mission.title).toBe("Escort a ship to a level 3 system"); + expect(mission.parts.length).toBe(1); + expect(mission.parts[0] instanceof MissionPartEscort).toBe(true); + let escort = mission.parts[0]; + expect(escort.destination).toBe(loc3); + }); + }); +} diff --git a/src/core/missions/MissionGenerator.ts b/src/core/missions/MissionGenerator.ts new file mode 100644 index 0000000..f522f64 --- /dev/null +++ b/src/core/missions/MissionGenerator.ts @@ -0,0 +1,45 @@ +module TS.SpaceTac { + /** + * Random generator of secondary missions that can be taken from + */ + export class MissionGenerator { + universe: Universe + level: number + around: StarLocation + random: RandomGenerator + + constructor(universe: Universe, level: number, around: StarLocation, random = RandomGenerator.global) { + this.universe = universe; + this.level = level; + this.around = around; + this.random = random; + } + + /** + * Generate a single mission + */ + generate(): Mission { + let generators = [ + bound(this, "generateEscort") + ]; + + let generator = this.random.choice(generators); + let result = generator(); + // TODO Add reward + return result; + } + + /** + * Generate an escort mission + */ + generateEscort(): Mission { + let mission = new Mission(this.universe); + let ship = new Ship(); + let dest_star = minBy(this.around.star.getNeighbors(), star => Math.abs(star.level - this.level)); + let destination = this.random.choice(dest_star.locations); + mission.addPart(new MissionPartEscort(mission, destination, ship)); + mission.title = `Escort a ship to a level ${dest_star.level} system`; + return mission; + } + } +} diff --git a/src/core/missions/MissionPartDialog.spec.ts b/src/core/missions/MissionPartConversation.spec.ts similarity index 86% rename from src/core/missions/MissionPartDialog.spec.ts rename to src/core/missions/MissionPartConversation.spec.ts index 0ed8087..fd27c0c 100644 --- a/src/core/missions/MissionPartDialog.spec.ts +++ b/src/core/missions/MissionPartConversation.spec.ts @@ -1,11 +1,11 @@ module TS.SpaceTac.Specs { - describe("MissionPartDialog", () => { - it("advances through dialog", function () { + describe("MissionPartConversation", () => { + it("advances through conversation", function () { let universe = new Universe(); let fleet = new Fleet(); let ship1 = new Ship(null, "Tim"); let ship2 = new Ship(null, "Ben"); - let part = new MissionPartDialog(new Mission(universe, fleet), [ship1, ship2], "Talk to Tim"); + let part = new MissionPartConversation(new Mission(universe, fleet), [ship1, ship2], "Talk to Tim"); expect(part.title).toEqual("Talk to Tim"); expect(part.checkCompleted()).toBe(true, "No dialog piece"); @@ -36,7 +36,7 @@ module TS.SpaceTac.Specs { let universe = new Universe(); let fleet = new Fleet(); let ship = new Ship(null, "Tim"); - let part = new MissionPartDialog(new Mission(universe, fleet), [ship]); + let part = new MissionPartConversation(new Mission(universe, fleet), [ship]); part.addPiece(null, "Hello !"); part.addPiece(ship, "Hiya !"); diff --git a/src/core/missions/MissionPartDialog.ts b/src/core/missions/MissionPartConversation.ts similarity index 86% rename from src/core/missions/MissionPartDialog.ts rename to src/core/missions/MissionPartConversation.ts index e9295d7..3bff2bd 100644 --- a/src/core/missions/MissionPartDialog.ts +++ b/src/core/missions/MissionPartConversation.ts @@ -2,9 +2,9 @@ module TS.SpaceTac { /** - * A single dialog piece + * A single conversation piece */ - interface DialogPiece { + interface ConversationPiece { // Interlocutor (null for the player's fleet) interlocutor: Ship | null @@ -13,14 +13,14 @@ module TS.SpaceTac { } /** - * A mission part that triggers a dialog + * A mission part that triggers a conversation */ - export class MissionPartDialog extends MissionPart { + export class MissionPartConversation extends MissionPart { // Other ships with which the dialog will take place interlocutors: Ship[] // Pieces of dialog - pieces: DialogPiece[] = [] + pieces: ConversationPiece[] = [] // Current piece current_piece = 0 @@ -70,7 +70,7 @@ module TS.SpaceTac { /** * Get the current piece of dialog */ - getCurrent(): DialogPiece { + getCurrent(): ConversationPiece { if (this.checkCompleted()) { return { interlocutor: null, @@ -88,7 +88,7 @@ module TS.SpaceTac { /** * Get the interlocutor from the player fleet that will say the piece */ - private getFleetInterlocutor(piece: DialogPiece): Ship | null { + private getFleetInterlocutor(piece: ConversationPiece): Ship | null { if (this.fleet.ships.length > 0) { // TODO Choose a ship by its personality traits return this.fleet.ships[0]; diff --git a/src/ui/Preload.ts b/src/ui/Preload.ts index 8425d29..01b0594 100644 --- a/src/ui/Preload.ts +++ b/src/ui/Preload.ts @@ -18,6 +18,7 @@ module TS.SpaceTac.UI { this.loadImage("common/arrow.png"); this.loadImage("common/button-ok.png"); this.loadImage("common/button-cancel.png"); + this.loadImage("common/dialog.png"); this.loadSheet("common/dialog-close.png", 92, 82); this.loadImage("menu/title.png"); this.loadImage("menu/button.png"); @@ -70,6 +71,7 @@ module TS.SpaceTac.UI { this.loadImage("map/location-warp.png"); this.loadSheet("map/status.png", 32); this.loadSheet("map/missions.png", 70); + this.loadSheet("map/mission-action.png", 192, 56); this.loadImage("character/sheet.png"); this.loadImage("character/close.png"); this.loadImage("character/ship.png"); diff --git a/src/ui/common/UIComponent.ts b/src/ui/common/UIComponent.ts index 925b8db..be87a89 100644 --- a/src/ui/common/UIComponent.ts +++ b/src/ui/common/UIComponent.ts @@ -231,8 +231,8 @@ module TS.SpaceTac.UI { /** * Add a static image, positioning its center. */ - addImage(x: number, y: number, key: string, scale = 1): void { - let image = new Phaser.Image(this.container.game, x, y, key); + addImage(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); this.addInternalChild(image); diff --git a/src/ui/common/UIDialog.ts b/src/ui/common/UIDialog.ts index b0dfc0e..7db82b8 100644 --- a/src/ui/common/UIDialog.ts +++ b/src/ui/common/UIDialog.ts @@ -7,7 +7,7 @@ module TS.SpaceTac.UI { * When a modal dialog opens, an overlay is displayed behind it to prevent clicking through it */ export class UIDialog extends UIComponent { - constructor(parent: BaseView, width: number, height: number, background: string) { + constructor(parent: BaseView, width = 1495, height = 1080, background = "common-dialog") { super(parent, width, height, background); if (parent.dialogs_layer.children.length == 0) { @@ -23,6 +23,7 @@ module TS.SpaceTac.UI { */ addOverlay(layer: Phaser.Group): void { let overlay = layer.game.add.button(0, 0, "common-transparent", () => null); + overlay.input.useHandCursor = false; overlay.scale.set(this.view.getWidth() / overlay.width, this.view.getHeight() / overlay.height); layer.add(overlay); } @@ -30,7 +31,7 @@ module TS.SpaceTac.UI { /** * Add a close button */ - addCloseButton(key: string, x: number, y: number, frame = 0, frame_hover = 1): void { + addCloseButton(key = "common-dialog-close", x = 1325, y = 131, frame = 0, frame_hover = 1): void { this.addButton(x, y, () => this.close(), key, frame, frame_hover, "Close this dialog"); } diff --git a/src/ui/map/ActiveMissionsDisplay.ts b/src/ui/map/ActiveMissionsDisplay.ts index c8aedbf..4990788 100644 --- a/src/ui/map/ActiveMissionsDisplay.ts +++ b/src/ui/map/ActiveMissionsDisplay.ts @@ -8,7 +8,7 @@ module TS.SpaceTac.UI { private missions: ActiveMissions constructor(parent: BaseView, missions: ActiveMissions) { - super(parent, 520, 210); + super(parent, 520, 240); this.missions = missions; this.update(); @@ -21,10 +21,11 @@ module TS.SpaceTac.UI { this.clearContent(); let active = this.missions.getCurrent(); - let offset = 245 - active.length * 70; + let spacing = 80; + let offset = 245 - active.length * spacing; active.forEach((mission, idx) => { - this.addImage(35, offset + 70 * idx, "map-missions"); - this.addText(90, offset + 70 * idx, mission.current_part.title, "#d2e1f3", 22, false, false, 430, true); + this.addImage(35, offset + spacing * idx, "map-missions", mission.main ? 0 : 1); + this.addText(90, offset + spacing * idx, mission.current_part.title, "#d2e1f3", 20, false, false, 430, true); }); } } diff --git a/src/ui/map/ConversationDisplay.ts b/src/ui/map/ConversationDisplay.ts index aa252df..64af708 100644 --- a/src/ui/map/ConversationDisplay.ts +++ b/src/ui/map/ConversationDisplay.ts @@ -3,7 +3,7 @@ module TS.SpaceTac.UI { * Display of an active conversation */ export class ConversationDisplay extends UIComponent { - dialog: MissionPartDialog | null = null + dialog: MissionPartConversation | null = null player: Player on_end: Function | null = null @@ -21,7 +21,7 @@ module TS.SpaceTac.UI { */ updateFromMissions(missions: ActiveMissions, on_end: Function | null = null) { let parts = missions.getCurrent().map(mission => mission.current_part); - this.dialog = first(parts, part => part instanceof MissionPartDialog); + this.dialog = first(parts, part => part instanceof MissionPartConversation); if (this.dialog) { this.on_end = on_end; diff --git a/src/ui/map/MapLocationMenu.ts b/src/ui/map/MapLocationMenu.ts index d1059d1..f96cde9 100644 --- a/src/ui/map/MapLocationMenu.ts +++ b/src/ui/map/MapLocationMenu.ts @@ -34,7 +34,9 @@ module TS.SpaceTac.UI { if (location) { let actions: [string, Function][] = []; if (location.shop) { + let shop = location.shop; actions.push(["Go to dockyard", () => view.openShop()]); + actions.push(["Show jobs", () => new MissionsDialog(view, shop, view.player)]); } switch (location.type) { diff --git a/src/ui/map/MissionsDialog.ts b/src/ui/map/MissionsDialog.ts new file mode 100644 index 0000000..24392e9 --- /dev/null +++ b/src/ui/map/MissionsDialog.ts @@ -0,0 +1,69 @@ +module TS.SpaceTac.UI { + /** + * Dialog to show available missions + */ + export class MissionsDialog extends UIDialog { + shop: Shop + player: Player + location: StarLocation + + constructor(view: BaseView, shop: Shop, player: Player) { + super(view); + + this.shop = shop; + this.player = player; + this.location = player.fleet.location || new StarLocation(); + + this.refresh(); + } + + /** + * Refresh the dialog content + */ + refresh() { + this.clearContent(); + this.addCloseButton(); + + let offset = 160; + + let active = this.player.missions.getCurrent().filter(mission => !mission.main); + if (active.length) { + this.addText(this.width / 2, offset, "Active jobs", "#b8d2f1", 36); + offset += 110; + + active.forEach(mission => { + this.addMission(offset, mission.title, "Reward: ???", 0, () => null); + offset += 110; + }); + } + + let proposed = this.shop.getMissions(this.location); + if (proposed.length) { + this.addText(this.width / 2, offset, "Proposed jobs", "#b8d2f1", 36); + offset += 110; + + proposed.forEach(mission => { + this.addMission(offset, mission.title, "Reward: ???", 2, () => { + this.shop.acceptMission(mission, this.player); + this.refresh(); + }); + offset += 110; + }); + } + } + + /** + * Add a mission text + */ + addMission(yoffset: number, title: string, subtitle: string, button_frame: number, button_callback: Function) { + this.addImage(320, yoffset, "map-missions", 1); + if (title) { + this.addText(380, yoffset - 15, title, "#d2e1f3", 22, false, false, 620, true); + } + if (subtitle) { + this.addText(380, yoffset + 22, subtitle, "#d2e1f3", 20, false, false, 620, true); + } + this.addButton(1120, yoffset, button_callback, "map-mission-action", button_frame, button_frame + 1); + } + } +} \ No newline at end of file