Added dialogs in missions
This commit is contained in:
parent
74c0cf6856
commit
f14ac531b7
|
@ -52,7 +52,7 @@ module TS.SpaceTac {
|
|||
*/
|
||||
setVisited(location: StarLocation): void {
|
||||
add(this.visited, location);
|
||||
this.missions.checkStatus(this.fleet, this.universe);
|
||||
this.missions.checkStatus();
|
||||
}
|
||||
|
||||
// Get currently played battle, null when none is in progress
|
||||
|
@ -61,7 +61,7 @@ module TS.SpaceTac {
|
|||
}
|
||||
setBattle(battle: Battle | null): void {
|
||||
this.fleet.setBattle(battle);
|
||||
this.missions.checkStatus(this.fleet, this.universe);
|
||||
this.missions.checkStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,12 +13,17 @@ module TS.SpaceTac.Specs {
|
|||
|
||||
it("gets the current list of missions, and updates them", function () {
|
||||
let missions = new ActiveMissions();
|
||||
let universe = new Universe();
|
||||
let fleet = new Fleet();
|
||||
|
||||
missions.main = new Mission([new MissionPart("Do something")]);
|
||||
missions.main = new Mission(universe, fleet);
|
||||
missions.main.addPart(new MissionPart(missions.main, "Do something"));
|
||||
missions.secondary = [
|
||||
new Mission([new MissionPart("Maybe do something")]),
|
||||
new Mission([new MissionPart("Surely do something")])
|
||||
new Mission(universe, fleet),
|
||||
new Mission(universe, fleet)
|
||||
];
|
||||
missions.secondary[0].addPart(new MissionPart(missions.secondary[0], "Maybe do something"));
|
||||
missions.secondary[1].addPart(new MissionPart(missions.secondary[1], "Surely do something"));
|
||||
|
||||
expect(missions.getCurrent().map(mission => mission.current_part.title)).toEqual([
|
||||
"Do something",
|
||||
|
@ -26,9 +31,7 @@ module TS.SpaceTac.Specs {
|
|||
"Surely do something",
|
||||
]);
|
||||
|
||||
let universe = new Universe();
|
||||
let fleet = new Fleet();
|
||||
missions.checkStatus(fleet, universe);
|
||||
missions.checkStatus();
|
||||
|
||||
expect(missions.getCurrent().map(mission => mission.current_part.title)).toEqual([
|
||||
"Do something",
|
||||
|
@ -37,7 +40,7 @@ module TS.SpaceTac.Specs {
|
|||
]);
|
||||
|
||||
spyOn(missions.secondary[0].current_part, "checkCompleted").and.returnValue(true);
|
||||
missions.checkStatus(fleet, universe);
|
||||
missions.checkStatus();
|
||||
|
||||
expect(missions.getCurrent().map(mission => mission.current_part.title)).toEqual([
|
||||
"Do something",
|
||||
|
@ -45,7 +48,7 @@ module TS.SpaceTac.Specs {
|
|||
]);
|
||||
|
||||
spyOn(missions.main.current_part, "checkCompleted").and.returnValue(true);
|
||||
missions.checkStatus(fleet, universe);
|
||||
missions.checkStatus();
|
||||
|
||||
expect(missions.getCurrent().map(mission => mission.current_part.title)).toEqual([
|
||||
"Surely do something",
|
||||
|
|
|
@ -32,13 +32,13 @@ module TS.SpaceTac {
|
|||
*
|
||||
* This will remove ended missions
|
||||
*/
|
||||
checkStatus(fleet: Fleet, universe: Universe): void {
|
||||
checkStatus(): void {
|
||||
if (this.main) {
|
||||
if (!this.main.checkStatus(fleet, universe)) {
|
||||
if (!this.main.checkStatus()) {
|
||||
this.main = null;
|
||||
}
|
||||
}
|
||||
this.secondary = this.secondary.filter(mission => mission.checkStatus(fleet, universe));
|
||||
this.secondary = this.secondary.filter(mission => mission.checkStatus());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,10 @@ module TS.SpaceTac.Specs {
|
|||
checkPart(story, 0, "^Find your contact in .* system$");
|
||||
|
||||
goTo(fleet, (<MissionPartGoTo>story.current_part).destination);
|
||||
expect(story.completed).toBe(true);
|
||||
checkPart(story, 1, "^Speak with your contact .*$");
|
||||
|
||||
(<MissionPartDialog>story.current_part).skip();
|
||||
expect(story.checkStatus()).toBe(false, "story not complete");
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
/// <reference path="Mission.ts" />
|
||||
|
||||
module TS.SpaceTac {
|
||||
function randomLocation(stars: Star[], excludes: StarLocation[] = []) {
|
||||
let random = RandomGenerator.global;
|
||||
function randomLocation(random: RandomGenerator, stars: Star[], excludes: StarLocation[] = []) {
|
||||
let star = stars.length == 1 ? stars[0] : random.choice(stars);
|
||||
return RandomGenerator.global.choice(star.locations.filter(loc => !contains(excludes, loc)));
|
||||
}
|
||||
|
@ -12,12 +11,27 @@ module TS.SpaceTac {
|
|||
*/
|
||||
export class MainStory extends Mission {
|
||||
constructor(universe: Universe, fleet: Fleet) {
|
||||
let random = RandomGenerator.global;
|
||||
let location = nn(fleet.location);
|
||||
super(universe, fleet, true);
|
||||
|
||||
super([
|
||||
new MissionPartGoTo(randomLocation([location.star], [location]), "Find your contact")
|
||||
], true);
|
||||
let random = RandomGenerator.global;
|
||||
let start_location = nn(fleet.location);
|
||||
|
||||
// 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"));
|
||||
let 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...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,34 +1,33 @@
|
|||
module TS.SpaceTac.Specs {
|
||||
describe("Mission", () => {
|
||||
it("check step status", function () {
|
||||
let mission = new Mission([
|
||||
new MissionPart("Part 1"),
|
||||
new MissionPart("Part 2")
|
||||
]);
|
||||
let universe = new Universe();
|
||||
let fleet = new Fleet();
|
||||
let mission = new Mission(universe, fleet);
|
||||
mission.addPart(new MissionPart(mission, "Part 1"));
|
||||
mission.addPart(new MissionPart(mission, "Part 2"));
|
||||
|
||||
expect(mission.current_part).toBe(mission.parts[0]);
|
||||
|
||||
let result = mission.checkStatus(fleet, universe);
|
||||
let result = mission.checkStatus();
|
||||
expect(result).toBe(true);
|
||||
expect(mission.current_part).toBe(mission.parts[0]);
|
||||
|
||||
spyOn(mission.parts[0], "checkCompleted").and.returnValues(false, true);
|
||||
|
||||
result = mission.checkStatus(fleet, universe);
|
||||
result = mission.checkStatus();
|
||||
expect(result).toBe(true);
|
||||
expect(mission.current_part).toBe(mission.parts[0]);
|
||||
result = mission.checkStatus(fleet, universe);
|
||||
result = mission.checkStatus();
|
||||
expect(result).toBe(true);
|
||||
expect(mission.current_part).toBe(mission.parts[1]);
|
||||
result = mission.checkStatus(fleet, universe);
|
||||
result = mission.checkStatus();
|
||||
expect(result).toBe(true);
|
||||
expect(mission.current_part).toBe(mission.parts[1]);
|
||||
|
||||
spyOn(mission.parts[1], "checkCompleted").and.returnValue(true);
|
||||
|
||||
result = mission.checkStatus(fleet, universe);
|
||||
result = mission.checkStatus();
|
||||
expect(result).toBe(false);
|
||||
expect(mission.current_part).toBe(mission.parts[1]);
|
||||
})
|
||||
|
|
|
@ -3,6 +3,12 @@ module TS.SpaceTac {
|
|||
* A mission (or quest) assigned to the player
|
||||
*/
|
||||
export class Mission {
|
||||
// Link to the fleet this mission has been assigned to
|
||||
fleet: Fleet
|
||||
|
||||
// Link to the universe in which the mission plays
|
||||
universe: Universe
|
||||
|
||||
// Indicator that the quest is part of the main story arc
|
||||
main: boolean
|
||||
|
||||
|
@ -15,11 +21,27 @@ module TS.SpaceTac {
|
|||
// Indicator that the mission is completed
|
||||
completed: boolean
|
||||
|
||||
constructor(parts: MissionPart[], main = false) {
|
||||
constructor(universe: Universe, fleet: Fleet, main = false) {
|
||||
this.universe = universe;
|
||||
this.fleet = fleet;
|
||||
this.main = main;
|
||||
this.parts = parts;
|
||||
this.current_part = parts[0];
|
||||
this.parts = [];
|
||||
this.completed = false;
|
||||
this.current_part = new MissionPart(this, "Empty mission");
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a part to the mission.
|
||||
*/
|
||||
addPart<T extends MissionPart>(part: T): T {
|
||||
if (part.mission === this) {
|
||||
this.parts.push(part);
|
||||
if (this.parts.length == 1) {
|
||||
this.current_part = this.parts[0];
|
||||
}
|
||||
this.completed = false;
|
||||
}
|
||||
return part;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -27,10 +49,10 @@ module TS.SpaceTac {
|
|||
*
|
||||
* Returns true if the mission is still active.
|
||||
*/
|
||||
checkStatus(fleet: Fleet, universe: Universe): boolean {
|
||||
checkStatus(): boolean {
|
||||
if (this.completed) {
|
||||
return false;
|
||||
} else if (this.current_part.checkCompleted(fleet, universe)) {
|
||||
} else if (this.current_part.checkCompleted()) {
|
||||
let current_index = this.parts.indexOf(this.current_part);
|
||||
if (current_index < 0 || current_index >= this.parts.length - 1) {
|
||||
this.completed = true;
|
||||
|
|
|
@ -3,18 +3,37 @@ module TS.SpaceTac {
|
|||
* An abstract part of a mission, describing the goal
|
||||
*/
|
||||
export class MissionPart {
|
||||
// Link to mission
|
||||
mission: Mission
|
||||
|
||||
// Very short description
|
||||
title: string
|
||||
|
||||
constructor(title: string) {
|
||||
constructor(mission: Mission, title: string) {
|
||||
this.mission = mission;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
get universe(): Universe {
|
||||
return this.mission.universe;
|
||||
}
|
||||
get fleet(): Fleet {
|
||||
return this.mission.fleet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract checking if the part is completed
|
||||
*/
|
||||
checkCompleted(fleet: Fleet, universe: Universe): boolean {
|
||||
checkCompleted(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force the part as completed
|
||||
*
|
||||
* This is a cheat, and should enforce the part conditions
|
||||
*/
|
||||
forceComplete(): void {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
52
src/core/missions/MissionPartDialog.spec.ts
Normal file
52
src/core/missions/MissionPartDialog.spec.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
module TS.SpaceTac.Specs {
|
||||
describe("MissionPartGoTo", () => {
|
||||
it("advances through dialog", 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");
|
||||
|
||||
expect(part.title).toEqual("Talk to Tim");
|
||||
expect(part.checkCompleted()).toBe(true, "No dialog piece");
|
||||
|
||||
part.addPiece(ship1, "Hi !");
|
||||
part.addPiece(ship2, "Indeed, hi !");
|
||||
part.addPiece(null, "Hum, hello.");
|
||||
expect(part.checkCompleted()).toBe(false, "Dialog pieces added");
|
||||
expect(part.getCurrent()).toEqual({ interlocutor: ship1, message: "Hi !" });
|
||||
|
||||
part.next();
|
||||
expect(part.checkCompleted()).toBe(false, "Second piece");
|
||||
expect(part.getCurrent()).toEqual({ interlocutor: ship2, message: "Indeed, hi !" });
|
||||
|
||||
part.next();
|
||||
expect(part.checkCompleted()).toBe(false, "Last piece");
|
||||
expect(part.getCurrent()).toEqual({ interlocutor: null, message: "Hum, hello." });
|
||||
|
||||
let ship = fleet.addShip();
|
||||
expect(part.getCurrent()).toEqual({ interlocutor: ship, message: "Hum, hello." });
|
||||
|
||||
part.next();
|
||||
expect(part.checkCompleted()).toBe(true, "Dialog ended");
|
||||
expect(part.getCurrent()).toEqual({ interlocutor: null, message: "" });
|
||||
})
|
||||
|
||||
it("force completes", function () {
|
||||
let universe = new Universe();
|
||||
let fleet = new Fleet();
|
||||
let ship = new Ship(null, "Tim");
|
||||
let part = new MissionPartDialog(new Mission(universe, fleet), [ship]);
|
||||
part.addPiece(null, "Hello !");
|
||||
part.addPiece(ship, "Hiya !");
|
||||
|
||||
expect(part.title).toEqual("Speak with Tim");
|
||||
expect(part.checkCompleted()).toBe(false);
|
||||
expect(part.getCurrent()).toEqual({ interlocutor: null, message: "Hello !" });
|
||||
|
||||
part.forceComplete();
|
||||
expect(part.checkCompleted()).toBe(true);
|
||||
expect(part.getCurrent()).toEqual({ interlocutor: null, message: "" });
|
||||
});
|
||||
})
|
||||
}
|
100
src/core/missions/MissionPartDialog.ts
Normal file
100
src/core/missions/MissionPartDialog.ts
Normal file
|
@ -0,0 +1,100 @@
|
|||
/// <reference path="MissionPart.ts" />
|
||||
|
||||
module TS.SpaceTac {
|
||||
/**
|
||||
* A single dialog piece
|
||||
*/
|
||||
interface DialogPiece {
|
||||
// Interlocutor (null for the player's fleet)
|
||||
interlocutor: Ship | null
|
||||
|
||||
// Text message
|
||||
message: string
|
||||
}
|
||||
|
||||
/**
|
||||
* A mission part that triggers a dialog
|
||||
*/
|
||||
export class MissionPartDialog extends MissionPart {
|
||||
// Other ships with which the dialog will take place
|
||||
interlocutors: Ship[]
|
||||
|
||||
// Pieces of dialog
|
||||
pieces: DialogPiece[] = []
|
||||
|
||||
// Current piece
|
||||
current_piece = 0
|
||||
|
||||
constructor(mission: Mission, interlocutors: Ship[], directive = "Speak with") {
|
||||
super(mission, `${directive} ${interlocutors[0].name}`);
|
||||
|
||||
this.interlocutors = interlocutors;
|
||||
}
|
||||
|
||||
checkCompleted(): boolean {
|
||||
return this.current_piece >= this.pieces.length;
|
||||
}
|
||||
|
||||
forceComplete(): void {
|
||||
this.skip();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a piece of dialog
|
||||
*/
|
||||
addPiece(interlocutor: Ship | null, message: string): void {
|
||||
this.pieces.push({
|
||||
interlocutor: interlocutor,
|
||||
message: message
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Go to the next dialog "screen"
|
||||
*
|
||||
* Returns true if there is still dialog to display.
|
||||
*/
|
||||
next(): boolean {
|
||||
this.current_piece += 1;
|
||||
return !this.checkCompleted();
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip to the end
|
||||
*/
|
||||
skip() {
|
||||
while (this.next()) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current piece of dialog
|
||||
*/
|
||||
getCurrent(): DialogPiece {
|
||||
if (this.checkCompleted()) {
|
||||
return {
|
||||
interlocutor: null,
|
||||
message: ""
|
||||
}
|
||||
} else {
|
||||
let piece = this.pieces[this.current_piece];
|
||||
return {
|
||||
interlocutor: piece.interlocutor || this.getFleetInterlocutor(piece),
|
||||
message: piece.message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the interlocutor from the player fleet that will say the piece
|
||||
*/
|
||||
private getFleetInterlocutor(piece: DialogPiece): Ship | null {
|
||||
if (this.fleet.ships.length > 0) {
|
||||
// TODO Choose a ship by its personality traits
|
||||
return this.fleet.ships[0];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,25 +3,38 @@ module TS.SpaceTac.Specs {
|
|||
it("completes when the fleet is at location, without encounter", function () {
|
||||
let destination = new StarLocation(new Star(null, 0, 0, "Atanax"));
|
||||
destination.encounter_random = new SkewedRandomGenerator([0], true);
|
||||
let part = new MissionPartGoTo(destination, "Collect gems");
|
||||
|
||||
let universe = new Universe();
|
||||
let fleet = new Fleet();
|
||||
let part = new MissionPartGoTo(new Mission(universe, fleet), destination, "Collect gems");
|
||||
|
||||
expect(part.title).toEqual("Collect gems in Atanax system");
|
||||
expect(part.checkCompleted(fleet, universe)).toBe(false, "Init location");
|
||||
expect(part.checkCompleted()).toBe(false, "Init location");
|
||||
|
||||
fleet.setLocation(destination, true);
|
||||
expect(part.checkCompleted(fleet, universe)).toBe(false, "Encounter not clear");
|
||||
expect(part.checkCompleted()).toBe(false, "Encounter not clear");
|
||||
|
||||
destination.clearEncounter();
|
||||
expect(part.checkCompleted(fleet, universe)).toBe(true, "Encouter cleared");
|
||||
expect(part.checkCompleted()).toBe(true, "Encouter cleared");
|
||||
|
||||
fleet.setLocation(new StarLocation(), true);
|
||||
expect(part.checkCompleted(fleet, universe)).toBe(false, "Went to another system");
|
||||
expect(part.checkCompleted()).toBe(false, "Went to another system");
|
||||
|
||||
fleet.setLocation(destination, true);
|
||||
expect(part.checkCompleted(fleet, universe)).toBe(true, "Back at destination");
|
||||
expect(part.checkCompleted()).toBe(true, "Back at destination");
|
||||
})
|
||||
|
||||
it("force completes", function () {
|
||||
let destination = new StarLocation(new Star(null, 0, 0, "Atanax"));
|
||||
destination.encounter_random = new SkewedRandomGenerator([0], true);
|
||||
|
||||
let universe = new Universe();
|
||||
let fleet = new Fleet();
|
||||
let part = new MissionPartGoTo(new Mission(universe, fleet), destination, "Investigate");
|
||||
|
||||
expect(part.checkCompleted()).toBe(false);
|
||||
part.forceComplete();
|
||||
expect(part.checkCompleted()).toBe(true);
|
||||
});
|
||||
})
|
||||
}
|
||||
|
|
|
@ -7,14 +7,19 @@ module TS.SpaceTac {
|
|||
export class MissionPartGoTo extends MissionPart {
|
||||
destination: StarLocation
|
||||
|
||||
constructor(destination: StarLocation, directive: string, hint = true) {
|
||||
super(hint ? `${directive} in ${destination.star.name} system` : directive);
|
||||
constructor(mission: Mission, destination: StarLocation, directive: string, hint = true) {
|
||||
super(mission, hint ? `${directive} in ${destination.star.name} system` : directive);
|
||||
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
checkCompleted(fleet: Fleet, universe: Universe): boolean {
|
||||
return fleet.location === this.destination && this.destination.isClear();
|
||||
checkCompleted(): boolean {
|
||||
return this.fleet.location === this.destination && this.destination.isClear();
|
||||
}
|
||||
|
||||
forceComplete(): void {
|
||||
this.destination.clearEncounter();
|
||||
this.fleet.setLocation(this.destination, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
module TS.SpaceTac.UI {
|
||||
export type UIInternalComponent = Phaser.Group | Phaser.Image | Phaser.Button | Phaser.Sprite;
|
||||
export type UIInternalComponent = Phaser.Group | Phaser.Image | Phaser.Button | Phaser.Sprite | Phaser.Graphics;
|
||||
|
||||
export type UIImageInfo = string | { key: string, frame?: number, frame1?: number, frame2?: number };
|
||||
export type UITextInfo = { content: string, color: string, size: number, bold?: boolean };
|
||||
|
@ -31,12 +31,12 @@ module TS.SpaceTac.UI {
|
|||
* Base class for UI components
|
||||
*/
|
||||
export class UIComponent {
|
||||
private has_background: boolean
|
||||
protected readonly view: BaseView;
|
||||
protected readonly parent: UIComponent | null;
|
||||
private readonly container: UIInternalComponent;
|
||||
protected readonly width: number;
|
||||
protected readonly height: number;
|
||||
private background: Phaser.Image | Phaser.Graphics | null
|
||||
protected readonly view: BaseView
|
||||
protected readonly parent: UIComponent | null
|
||||
private readonly container: Phaser.Group
|
||||
protected readonly width: number
|
||||
protected readonly height: number
|
||||
|
||||
constructor(parent: BaseView | UIComponent, width: number, height: number, background_key: string | null = null) {
|
||||
this.width = width;
|
||||
|
@ -58,10 +58,9 @@ module TS.SpaceTac.UI {
|
|||
}
|
||||
|
||||
if (background_key) {
|
||||
this.addInternalChild(new Phaser.Image(this.view.game, 0, 0, background_key));
|
||||
this.has_background = true;
|
||||
this.background = this.addInternalChild(new Phaser.Image(this.view.game, 0, 0, background_key));
|
||||
} else {
|
||||
this.has_background = false;
|
||||
this.background = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,6 +76,29 @@ module TS.SpaceTac.UI {
|
|||
return `<${classname(this)}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a background
|
||||
*/
|
||||
drawBackground(fill: number, border?: number, border_width = 0, alpha = 1, mouse_capture?: Function) {
|
||||
if (this.background) {
|
||||
this.background.destroy();
|
||||
}
|
||||
|
||||
this.background = this.addInternalChild(new Phaser.Graphics(this.game, 0, 0));
|
||||
if (border_width) {
|
||||
this.background.lineStyle(border_width, border);
|
||||
}
|
||||
this.background.beginFill(fill, alpha);
|
||||
this.background.drawRect(0, 0, this.width, this.height);
|
||||
this.background.endFill();
|
||||
|
||||
if (mouse_capture) {
|
||||
this.background.inputEnabled = true;
|
||||
this.background.input.useHandCursor = true;
|
||||
this.background.events.onInputUp.add(() => mouse_capture());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the a parent's layer
|
||||
*/
|
||||
|
@ -94,30 +116,23 @@ module TS.SpaceTac.UI {
|
|||
/**
|
||||
* Create the internal phaser node
|
||||
*/
|
||||
protected createInternalNode(): UIInternalComponent {
|
||||
protected createInternalNode(): Phaser.Group {
|
||||
return new Phaser.Group(this.view.game, undefined, classname(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an other internal component as child
|
||||
*/
|
||||
protected addInternalChild(child: UIInternalComponent): void {
|
||||
if (this.container instanceof Phaser.Group) {
|
||||
this.container.add(child);
|
||||
} else {
|
||||
this.container.addChild(child);
|
||||
}
|
||||
protected addInternalChild<T extends UIInternalComponent>(child: T): T {
|
||||
this.container.add(child);
|
||||
return child;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the component's visibility, with optional transition (in milliseconds)
|
||||
*/
|
||||
setVisible(visible: boolean, transition = 0): void {
|
||||
if (transition > 0) {
|
||||
this.view.animations.setVisible(this.container, visible, transition);
|
||||
} else {
|
||||
this.container.visible = visible;
|
||||
}
|
||||
this.view.animations.setVisible(this.container, visible, transition);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -180,9 +195,9 @@ module TS.SpaceTac.UI {
|
|||
* Clear from all added content.
|
||||
*/
|
||||
clearContent(): void {
|
||||
let offset = this.has_background ? 1 : 0;
|
||||
let offset = this.background ? 1 : 0;
|
||||
while (this.container.children.length > offset) {
|
||||
this.container.removeChildAt(offset);
|
||||
this.container.remove(this.container.children[offset], true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -150,7 +150,9 @@ module TS.SpaceTac.UI {
|
|||
*/
|
||||
protected message(message: string, layer = 2, clear = true): Function {
|
||||
return () => {
|
||||
let display = new ProgressiveMessage(this.view, 800, 150, message, true);
|
||||
let style = new ProgressiveMessageStyle();
|
||||
style.center = true;
|
||||
let display = new ProgressiveMessage(this.view, 900, 200, message, style);
|
||||
display.setPositionInsideParent(0.5, 0.9);
|
||||
display.moveToLayer(this.getLayer(layer, clear));
|
||||
display.setVisible(false);
|
||||
|
|
|
@ -1,12 +1,59 @@
|
|||
module TS.SpaceTac.UI {
|
||||
/**
|
||||
* Style for a message display
|
||||
*/
|
||||
export class ProgressiveMessageStyle {
|
||||
// Center the message or not
|
||||
center = false
|
||||
|
||||
// Padding between the content and the external border
|
||||
padding = 10
|
||||
|
||||
// Background fill color
|
||||
background = 0x202225
|
||||
alpha = 0.9
|
||||
|
||||
// Border color and width
|
||||
border = 0x404450
|
||||
border_width = 2
|
||||
|
||||
// Text font style
|
||||
text_color = "#ffffff"
|
||||
text_size = 20
|
||||
text_bold = true
|
||||
|
||||
// Portrait or image to display
|
||||
image = ""
|
||||
image_size = 0
|
||||
image_caption = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, center = false) {
|
||||
constructor(parent: BaseView | UIComponent, width: number, height: number, message: string, style = new ProgressiveMessageStyle()) {
|
||||
super(parent, width, height);
|
||||
|
||||
this.addText(center ? width / 2 : 0, 0, message, "#ffffff", 20, true, center, width);
|
||||
this.drawBackground(style.background, style.border, style.border_width, style.alpha);
|
||||
|
||||
let offset = 0;
|
||||
if (style.image_size && style.image) {
|
||||
offset = style.image_size + style.padding;
|
||||
width -= offset;
|
||||
|
||||
let ioffset = style.padding + Math.floor(style.image_size / 2);
|
||||
this.addImage(ioffset, ioffset, style.image);
|
||||
|
||||
if (style.image_caption) {
|
||||
let text_size = Math.ceil(style.text_size * 0.6);
|
||||
this.addText(ioffset, style.padding + style.image_size + text_size, style.image_caption,
|
||||
style.text_color, text_size, false, true, style.image_size);
|
||||
}
|
||||
}
|
||||
|
||||
this.addText(offset + (style.center ? width / 2 : style.padding), style.center ? height / 2 : style.padding, message,
|
||||
style.text_color, style.text_size, style.text_bold, style.center, width - style.padding * 2, style.center);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,9 +10,9 @@ module TS.SpaceTac.UI.Specs {
|
|||
let container = <Phaser.Group>(<any>display).container;
|
||||
expect(container.children.length).toBe(0);
|
||||
|
||||
missions.secondary.push(new Mission([
|
||||
new MissionPart("Get back to base")
|
||||
]));
|
||||
let mission = new Mission(new Universe(), new Fleet());
|
||||
mission.addPart(new MissionPart(mission, "Get back to base"));
|
||||
missions.secondary = [mission];
|
||||
|
||||
display.update();
|
||||
expect(container.children.length).toBe(2);
|
||||
|
|
94
src/ui/map/ConversationDisplay.ts
Normal file
94
src/ui/map/ConversationDisplay.ts
Normal file
|
@ -0,0 +1,94 @@
|
|||
module TS.SpaceTac.UI {
|
||||
/**
|
||||
* Display of an active conversation
|
||||
*/
|
||||
export class ConversationDisplay extends UIComponent {
|
||||
dialog: MissionPartDialog | null = null
|
||||
player: Player
|
||||
on_end: Function | null = null
|
||||
|
||||
constructor(parent: BaseView, player: Player) {
|
||||
super(parent, parent.getWidth(), parent.getHeight());
|
||||
|
||||
this.player = player;
|
||||
|
||||
this.drawBackground(0x404450, undefined, undefined, 0.7, () => this.nextPiece());
|
||||
this.setVisible(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update from currently active missions
|
||||
*/
|
||||
updateFromMissions(missions: ActiveMissions, on_end: Function | null = null) {
|
||||
let parts = missions.getCurrent().map(mission => mission.current_part);
|
||||
this.dialog = <MissionPartDialog | null>first(parts, part => part instanceof MissionPartDialog);
|
||||
|
||||
if (this.dialog) {
|
||||
this.on_end = on_end;
|
||||
} else {
|
||||
this.on_end = null;
|
||||
}
|
||||
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Go to the next dialog piece
|
||||
*/
|
||||
nextPiece(): void {
|
||||
if (this.dialog) {
|
||||
this.dialog.next();
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip the conversation
|
||||
*/
|
||||
skipConversation(): void {
|
||||
if (this.dialog) {
|
||||
this.dialog.skip();
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the displayed dialog piece
|
||||
*/
|
||||
refresh() {
|
||||
this.clearContent();
|
||||
|
||||
if (this.dialog) {
|
||||
if (this.dialog.checkCompleted()) {
|
||||
if (this.on_end) {
|
||||
this.on_end();
|
||||
this.on_end = null;
|
||||
}
|
||||
this.setVisible(false, 700);
|
||||
} else {
|
||||
let piece = this.dialog.getCurrent();
|
||||
|
||||
let style = new ProgressiveMessageStyle();
|
||||
if (piece.interlocutor) {
|
||||
style.image = `ship-${piece.interlocutor.model.code}-portrait`;
|
||||
style.image_caption = piece.interlocutor.name;
|
||||
style.image_size = 256;
|
||||
}
|
||||
|
||||
let message = new ProgressiveMessage(this, 900, 300, piece.message, style);
|
||||
message.addButton(840, 240, () => this.nextPiece(), "common-arrow");
|
||||
|
||||
if (piece.interlocutor && piece.interlocutor.getPlayer() === this.player) {
|
||||
message.setPositionInsideParent(0.1, 0.2);
|
||||
} else {
|
||||
message.setPositionInsideParent(0.9, 0.8);
|
||||
}
|
||||
|
||||
this.setVisible(true, 700);
|
||||
}
|
||||
} else {
|
||||
this.setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@ module TS.SpaceTac.UI {
|
|||
|
||||
// Active missions
|
||||
missions: ActiveMissionsDisplay
|
||||
conversation: ConversationDisplay
|
||||
|
||||
// Character sheet
|
||||
character_sheet: CharacterSheet
|
||||
|
@ -117,10 +118,21 @@ module TS.SpaceTac.UI {
|
|||
this.character_sheet.hide(false);
|
||||
this.layer_overlay.add(this.character_sheet);
|
||||
|
||||
this.conversation = new ConversationDisplay(this, this.player);
|
||||
this.conversation.moveToLayer(this.layer_overlay);
|
||||
|
||||
this.gameui.audio.startMusic("spring-thaw");
|
||||
|
||||
// Inputs
|
||||
this.inputs.bind(" ", "Conversation step", () => this.conversation.nextPiece());
|
||||
this.inputs.bind("Escape", "Skip conversation", () => this.conversation.skipConversation());
|
||||
this.inputs.bindCheat("r", "Reveal whole map", () => this.revealAll());
|
||||
this.inputs.bindCheat("n", "Next story step", () => {
|
||||
if (this.player.missions.main) {
|
||||
this.player.missions.main.current_part.forceComplete();
|
||||
this.backToRouter();
|
||||
}
|
||||
});
|
||||
|
||||
this.setZoom(2);
|
||||
|
||||
|
@ -161,6 +173,10 @@ module TS.SpaceTac.UI {
|
|||
this.actions.setFromLocation(this.player.fleet.location, this);
|
||||
|
||||
this.missions.update();
|
||||
this.conversation.updateFromMissions(this.player.missions, () => {
|
||||
this.player.missions.checkStatus();
|
||||
this.missions.update();
|
||||
});
|
||||
|
||||
if (interactive) {
|
||||
this.setInteractionEnabled(true);
|
||||
|
|
Loading…
Reference in a new issue