Added escort mission part
This commit is contained in:
parent
f7424692fe
commit
993ed0e897
67
TODO
67
TODO
|
@ -1,67 +0,0 @@
|
|||
* New battle internal flow: any game state change should be done through revertable events
|
||||
* UI: use a common component class, and a layer abstraction
|
||||
* Character sheet: add initial character creation
|
||||
* Character sheet: disable interaction during battle (except for loot screen)
|
||||
* Character sheet: improve eye-catching for shop and loot section
|
||||
* Character sheet: highlight allowed destinations during drag-and-drop, with text hints
|
||||
* Character sheet: when transferring to another ship, if the item can't be equipped (unmatched requirements), the transfer is cancelled instead of trying cargo
|
||||
* Character sheet: effective skill is sometimes not updated when upgrading base skill
|
||||
* Character sheet: tooltip to show the sources of attributes
|
||||
* Character sheet: add a "loot all" button
|
||||
* Shops: allow to change/buy ship model
|
||||
* Loot: lucky finds should be proportional to cargo space
|
||||
* Ship models: Add permanent effects
|
||||
* Ship models: Add permanent actions
|
||||
* Equipment: add critical hit/miss
|
||||
* Equipment: add damage over time effect
|
||||
* Menu: allow to delete cloud saves
|
||||
* Fix cloud save games with "Level 0 - 0 ships"
|
||||
* Arena: display effects description instead of attribute changes
|
||||
* Arena: display radius for area effects (both on action hover, and while action is active)
|
||||
* Arena: 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)
|
||||
* Arena: add engine trail
|
||||
* Log processor: Cancel previous animations, and allow no animation mode
|
||||
* Actions: fix targetting not resetting on current cursor location when using keyboard shortcuts
|
||||
* Add actions with cost dependent of distance (like current move actions)
|
||||
* Find incentives to move from starting position
|
||||
* Outcome: disable the loot button if there is no loot
|
||||
* Ensure that tweens and particle emitters get destroyed once animation is done (or view changes)
|
||||
* UI: add standard confirm dialog
|
||||
* Controls: do not focus on ship while targetting for area effects (dissociate hover and target)
|
||||
* Controls: fix hover being stuck when the cursor exits the window, or the item moves or is hidden
|
||||
* Drones: add hull points and take area damage
|
||||
* Drones: find a way to avoid arena cluttering
|
||||
* Drones: repair drone has its activation effect displayed as permanent effect on ships in the radius
|
||||
* Add a battle log display
|
||||
* Allow to undo last moves
|
||||
* Merge identical sticky effects
|
||||
* Allow to skip animations and AI delays in battle
|
||||
* Hide enemy information (shield, hull, weapons), until they are in play, or until a "spy" effect is used
|
||||
* Mobile: think UI layout so that fingers do not block the view (right and left handed)
|
||||
* Mobile: display tooltips larger and on the side of screen where the finger is not
|
||||
* Mobile: targetting in two times, using a draggable target indicator
|
||||
* AI: use a first batch of producers, and only if no "good" move has been found, go on with some infinite producers
|
||||
* AI: evaluate buffs/debuffs
|
||||
* AI: abandon fight
|
||||
* AI: add combination of random small move and actual maneuver, as producer
|
||||
* AI: new duel page with producers/evaluators tweaking
|
||||
* AI: work in a dedicated process
|
||||
* Map: remove jump links that cross the radius of other systems
|
||||
* Tutorial
|
||||
* Campaign: Add ship personality (with icons to identify ?), with reaction to battle and map movements
|
||||
* Campaign: Add factions and reputation
|
||||
* Campaign: Missions/quests system
|
||||
* Campaign: Main story arc
|
||||
|
||||
Equipment ideas:
|
||||
* Shield with toggle effect that absorbs damage in an area
|
||||
* Drive with minimal distance
|
||||
* Cooldown drone or ability
|
||||
|
||||
Later, if possible:
|
||||
* Animated arena background, instead of big picture
|
||||
* Invocation/reinforcements (need to up the 10 ships limit)
|
||||
* Dynamic music composition
|
||||
* Replays
|
||||
* Multiplayer/co-op
|
||||
* Formation or deployment phase
|
101
TODO.md
Normal file
101
TODO.md
Normal file
|
@ -0,0 +1,101 @@
|
|||
To-Do-list
|
||||
==========
|
||||
|
||||
Menu/settings/saves
|
||||
-------------------
|
||||
|
||||
* Allow to delete cloud saves
|
||||
* Fix cloud save games with "Level 0 - 0 ships"
|
||||
|
||||
Map/story
|
||||
---------
|
||||
|
||||
* Add initial character creation
|
||||
* Remove jump links that cross the radius of other systems
|
||||
* Fix quickly zooming in twice preventing to display some UI parts
|
||||
* Enemy fleet size should start low and increase with system level
|
||||
* Allow to change/buy ship model
|
||||
* Add ship personality (with icons to identify ?), with reaction dialogs
|
||||
* Add factions and reputation
|
||||
* Add generated missions with rewards
|
||||
* Show missions' destination near systems/locations
|
||||
|
||||
Character sheet
|
||||
---------------
|
||||
|
||||
* Disable interaction during battle (except for loot screen)
|
||||
* Improve eye-catching for shop and loot section
|
||||
* Highlight allowed destinations during drag-and-drop, with text hints
|
||||
* When transferring to another ship, if the item can't be equipped (unmatched requirements), the transfer is cancelled instead of trying cargo
|
||||
* Effective skill is sometimes not updated when upgrading base skill
|
||||
* Tooltip to show the sources of attributes
|
||||
* Fix ship list not refreshing when escorted ship is added or removed
|
||||
* Forbid to modify escorted ship
|
||||
* Add merged cargo display for the whole fleet
|
||||
|
||||
Battle
|
||||
------
|
||||
|
||||
* Add a voluntary retreat option
|
||||
* Display effects description instead of attribute changes
|
||||
* Display radius for area effects (both on action hover, and while action is active)
|
||||
* 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 ?)
|
||||
* Add a "loot all" button, disable the loot button if there is no loot
|
||||
* 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
|
||||
* Allow to undo last moves
|
||||
* Add a battle log display
|
||||
|
||||
Ships models and equipments
|
||||
---------------------------
|
||||
|
||||
* Add permanent effects and actions to ship models
|
||||
* Add critical hit/miss
|
||||
* Add damage over time effect (tricky to make intuitive)
|
||||
* Move distance should increase with maneuvrability
|
||||
* Chance to hit should increase with precision
|
||||
* Add actions with cost dependent of distance (like current move actions)
|
||||
* Add hull points to drones and make them take area damage
|
||||
|
||||
Artificial Intelligence
|
||||
-----------------------
|
||||
|
||||
* Use a first batch of producers, and only if no "good" move has been fo go on with some infinite producers
|
||||
* Evaluate buffs/debuffs
|
||||
* Abandon fight if the AI judges there is no hope of victory
|
||||
* Add combination of random small move and actual maneuver, as prer
|
||||
* New duel page with producers/evaluators tweaking
|
||||
* Work in a dedicated process (webworker)
|
||||
|
||||
Technical
|
||||
---------
|
||||
|
||||
* Ensure that tweens and particle emitters get destroyed once animation is done (or view changes)
|
||||
|
||||
Common UI
|
||||
---------
|
||||
|
||||
* Fix hover being stuck when the cursor exits the window, or the item moves or is hidden
|
||||
* Add a standard confirm dialog
|
||||
* Mobile: think UI layout so that fingers do not block the view (right and left handed)
|
||||
* Mobile: display tooltips larger and on the side of screen where the finger is not
|
||||
* Mobile: targetting in two times, using a draggable target indicator
|
||||
|
||||
Postponed
|
||||
---------
|
||||
|
||||
* Tutorial
|
||||
* Secondary story arcs
|
||||
* Replays
|
||||
* Multiplayer/co-op
|
||||
* Formation or deployment phase
|
||||
* 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
|
||||
* Invocation/reinforcements (need to up the 10 ships limit)
|
||||
* Dynamic music composition
|
|
@ -14,6 +14,39 @@ module TS.SpaceTac {
|
|||
expect(fleet.getLevel()).toEqual(4);
|
||||
});
|
||||
|
||||
it("adds and removes ships", function () {
|
||||
let fleet1 = new Fleet();
|
||||
let fleet2 = new Fleet();
|
||||
|
||||
let ship1 = fleet1.addShip();
|
||||
expect(fleet1.ships).toEqual([ship1]);
|
||||
expect(fleet2.ships).toEqual([]);
|
||||
|
||||
let ship2 = new Ship();
|
||||
expect(fleet1.ships).toEqual([ship1]);
|
||||
expect(fleet2.ships).toEqual([]);
|
||||
|
||||
fleet2.addShip(ship2);
|
||||
expect(fleet1.ships).toEqual([ship1]);
|
||||
expect(fleet2.ships).toEqual([ship2]);
|
||||
|
||||
fleet1.addShip(ship2);
|
||||
expect(fleet1.ships).toEqual([ship1, ship2]);
|
||||
expect(fleet2.ships).toEqual([]);
|
||||
|
||||
fleet1.removeShip(ship1, fleet2);
|
||||
expect(fleet1.ships).toEqual([ship2]);
|
||||
expect(fleet2.ships).toEqual([ship1]);
|
||||
|
||||
fleet1.removeShip(ship1);
|
||||
expect(fleet1.ships).toEqual([ship2]);
|
||||
expect(fleet2.ships).toEqual([ship1]);
|
||||
|
||||
fleet1.removeShip(ship2);
|
||||
expect(fleet1.ships).toEqual([]);
|
||||
expect(fleet2.ships).toEqual([ship1]);
|
||||
});
|
||||
|
||||
it("changes location, only using jumps to travel between systems", function () {
|
||||
let fleet = new Fleet();
|
||||
let system1 = new Star();
|
||||
|
@ -48,5 +81,32 @@ module TS.SpaceTac {
|
|||
expect(result).toBe(true);
|
||||
expect(fleet.location).toBe(jump1);
|
||||
});
|
||||
|
||||
it("checks if a fleet is alive", function () {
|
||||
let fleet = new Fleet();
|
||||
expect(fleet.isAlive()).toBe(false);
|
||||
|
||||
let ship1 = fleet.addShip();
|
||||
expect(fleet.isAlive()).toBe(true);
|
||||
|
||||
let ship2 = fleet.addShip();
|
||||
expect(fleet.isAlive()).toBe(true);
|
||||
|
||||
ship1.setDead();
|
||||
expect(fleet.isAlive()).toBe(true);
|
||||
|
||||
ship2.setDead();
|
||||
expect(fleet.isAlive()).toBe(false);
|
||||
|
||||
let ship3 = fleet.addShip();
|
||||
expect(fleet.isAlive()).toBe(true);
|
||||
|
||||
let ship4 = fleet.addShip();
|
||||
ship4.critical = true;
|
||||
expect(fleet.isAlive()).toBe(true);
|
||||
|
||||
ship4.setDead();
|
||||
expect(fleet.isAlive()).toBe(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -25,6 +25,10 @@ module TS.SpaceTac {
|
|||
this.ships = [];
|
||||
}
|
||||
|
||||
jasmineToString(): string {
|
||||
return `${this.player.name}'s fleet [${this.ships.map(ship => ship.name).join(",")}]`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current location of the fleet
|
||||
*
|
||||
|
@ -48,7 +52,9 @@ module TS.SpaceTac {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Add a ship in this fleet
|
||||
/**
|
||||
* Add a ship this fleet
|
||||
*/
|
||||
addShip(ship = new Ship()): Ship {
|
||||
if (ship.fleet && ship.fleet != this) {
|
||||
remove(ship.fleet.ships, ship);
|
||||
|
@ -58,6 +64,15 @@ module TS.SpaceTac {
|
|||
return ship;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the ship from this fleet, transferring it to another fleet
|
||||
*/
|
||||
removeShip(ship: Ship, fleet = new Fleet()): void {
|
||||
if (ship.fleet === this) {
|
||||
fleet.addShip(ship);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the current battle
|
||||
setBattle(battle: Battle | null): void {
|
||||
this.battle = battle;
|
||||
|
@ -77,15 +92,15 @@ module TS.SpaceTac {
|
|||
return Math.floor(avg);
|
||||
}
|
||||
|
||||
// Check if the fleet still has living ships
|
||||
/**
|
||||
* Check if the fleet is considered alive (at least one ship alive, and no critical ship dead)
|
||||
*/
|
||||
isAlive(): boolean {
|
||||
var count = 0;
|
||||
this.ships.forEach((ship: Ship) => {
|
||||
if (ship.alive) {
|
||||
count += 1;
|
||||
if (any(this.ships, ship => ship.critical && !ship.alive)) {
|
||||
return false;
|
||||
} else {
|
||||
return any(this.ships, ship => ship.alive);
|
||||
}
|
||||
});
|
||||
return (count > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ module TS.SpaceTac.Specs {
|
|||
expect(session.start_location.encounter_gen).toBe(true);
|
||||
|
||||
session.setCampaignFleet();
|
||||
expect(session.player.fleet.ships.length).toBe(4);
|
||||
expect(session.player.fleet.ships.length).toBe(2);
|
||||
expect(session.player.fleet.credits).toBe(500);
|
||||
expect(session.player.fleet.location).toBe(session.start_location);
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@ module TS.SpaceTac {
|
|||
* This represents the current state of game
|
||||
*/
|
||||
export class GameSession {
|
||||
// "Hopefully"" unique session id
|
||||
// "Hopefully" unique session id
|
||||
id: string
|
||||
|
||||
// Game universe
|
||||
|
@ -81,7 +81,7 @@ module TS.SpaceTac {
|
|||
this.player.fleet = fleet;
|
||||
} else {
|
||||
let fleet_generator = new FleetGenerator();
|
||||
this.player.fleet = fleet_generator.generate(1, this.player, 4);
|
||||
this.player.fleet = fleet_generator.generate(1, this.player, 2);
|
||||
}
|
||||
|
||||
this.player.fleet.setLocation(this.start_location);
|
||||
|
|
|
@ -70,6 +70,9 @@ module TS.SpaceTac {
|
|||
// Flag indicating if the ship is alive
|
||||
alive: boolean
|
||||
|
||||
// Flag indicating that the ship is mission critical (escorted ship)
|
||||
critical = false
|
||||
|
||||
// Position in the arena
|
||||
arena_x: number
|
||||
arena_y: number
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
module TS.SpaceTac.Specs {
|
||||
describe("MainStory", () => {
|
||||
function checkPart(story: Mission, index: number, title: string) {
|
||||
function checkPart(story: Mission, index: number, title: string, completed = false) {
|
||||
let result = story.checkStatus();
|
||||
expect(story.parts.indexOf(story.current_part)).toBe(index);
|
||||
expect(story.current_part.title).toMatch(title);
|
||||
expect(story.completed).toBe(false);
|
||||
expect(story.completed).toBe(completed);
|
||||
expect(result).toBe(!completed);
|
||||
}
|
||||
|
||||
function goTo(fleet: Fleet, location: StarLocation, win_encounter = true) {
|
||||
|
@ -25,12 +27,21 @@ module TS.SpaceTac.Specs {
|
|||
|
||||
let missions = session.player.missions;
|
||||
let story = nn(missions.main);
|
||||
checkPart(story, 0, "^Find your contact in .* system$");
|
||||
|
||||
goTo(fleet, (<MissionPartGoTo>story.current_part).destination);
|
||||
checkPart(story, 1, "^Speak with your contact .*$");
|
||||
let fleet_size = fleet.ships.length;
|
||||
|
||||
checkPart(story, 0, "^Travel to Terranax galaxy$");
|
||||
(<MissionPartDialog>story.current_part).skip();
|
||||
|
||||
checkPart(story, 1, "^Find your contact in .*$");
|
||||
goTo(fleet, (<MissionPartGoTo>story.current_part).destination);
|
||||
|
||||
checkPart(story, 2, "^Speak with your contact");
|
||||
(<MissionPartDialog>story.current_part).skip();
|
||||
|
||||
checkPart(story, 3, "^Go with .* in .* system$");
|
||||
expect(fleet.ships.length).toBe(fleet_size + 1);
|
||||
goTo(fleet, (<MissionPartEscort>story.current_part).destination);
|
||||
|
||||
expect(story.checkStatus()).toBe(false, "story not complete");
|
||||
})
|
||||
})
|
||||
|
|
|
@ -16,12 +16,18 @@ module TS.SpaceTac {
|
|||
let random = RandomGenerator.global;
|
||||
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.");
|
||||
|
||||
// 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"));
|
||||
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.");
|
||||
|
@ -32,6 +38,11 @@ module TS.SpaceTac {
|
|||
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...");
|
||||
|
||||
// Go take a look at the graveyard
|
||||
let nearby_systems = nna(start_location.star.getLinks().map(link => link.getPeer(contact_location.star)));
|
||||
let graveyard_location = randomLocation(random, [minBy(nearby_systems, system => system.level)]);
|
||||
this.addPart(new MissionPartEscort(this, graveyard_location, contact_character, `Go with ${contact_character.name} in ${graveyard_location.star.name} system`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,12 +53,15 @@ module TS.SpaceTac {
|
|||
if (this.completed) {
|
||||
return false;
|
||||
} else if (this.current_part.checkCompleted()) {
|
||||
this.current_part.onEnded();
|
||||
|
||||
let current_index = this.parts.indexOf(this.current_part);
|
||||
if (current_index < 0 || current_index >= this.parts.length - 1) {
|
||||
this.completed = true;
|
||||
return false;
|
||||
} else {
|
||||
this.current_part = this.parts[current_index + 1];
|
||||
this.current_part.onStarted();
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -35,5 +35,17 @@ module TS.SpaceTac {
|
|||
*/
|
||||
forceComplete(): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Event called when the part starts
|
||||
*/
|
||||
onStarted(): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Event called when the part ends
|
||||
*/
|
||||
onEnded(): void {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
module TS.SpaceTac.Specs {
|
||||
describe("MissionPartGoTo", () => {
|
||||
describe("MissionPartDialog", () => {
|
||||
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");
|
||||
let part = new MissionPartDialog(new Mission(universe, fleet), [ship1, ship2], "Talk to Tim");
|
||||
|
||||
expect(part.title).toEqual("Talk to Tim");
|
||||
expect(part.checkCompleted()).toBe(true, "No dialog piece");
|
||||
|
|
|
@ -25,8 +25,8 @@ module TS.SpaceTac {
|
|||
// Current piece
|
||||
current_piece = 0
|
||||
|
||||
constructor(mission: Mission, interlocutors: Ship[], directive = "Speak with") {
|
||||
super(mission, `${directive} ${interlocutors[0].name}`);
|
||||
constructor(mission: Mission, interlocutors: Ship[], directive?: string) {
|
||||
super(mission, directive || `Speak with ${interlocutors[0].name}`);
|
||||
|
||||
this.interlocutors = interlocutors;
|
||||
}
|
||||
|
|
67
src/core/missions/MissionPartEscort.spec.ts
Normal file
67
src/core/missions/MissionPartEscort.spec.ts
Normal file
|
@ -0,0 +1,67 @@
|
|||
module TS.SpaceTac.Specs {
|
||||
describe("MissionPartEscort", () => {
|
||||
it("completes when the fleet is at location, with its escort", 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 ship = new Ship(null, "Zybux");
|
||||
let part = new MissionPartEscort(new Mission(universe, fleet), destination, ship);
|
||||
|
||||
expect(fleet.ships).not.toContain(ship);
|
||||
expect(part.title).toEqual("Escort Zybux to Atanax system");
|
||||
expect(part.checkCompleted()).toBe(false, "Init location");
|
||||
|
||||
part.onStarted();
|
||||
expect(fleet.ships).toContain(ship);
|
||||
|
||||
fleet.setLocation(destination, true);
|
||||
expect(part.checkCompleted()).toBe(false, "Encounter not clear");
|
||||
|
||||
destination.clearEncounter();
|
||||
expect(part.checkCompleted()).toBe(true, "Encouter cleared");
|
||||
|
||||
fleet.setLocation(new StarLocation(), true);
|
||||
expect(part.checkCompleted()).toBe(false, "Went to another system");
|
||||
|
||||
fleet.setLocation(destination, true);
|
||||
expect(part.checkCompleted()).toBe(true, "Back at destination");
|
||||
expect(fleet.ships).toContain(ship);
|
||||
|
||||
part.onEnded();
|
||||
expect(fleet.ships).not.toContain(ship);
|
||||
})
|
||||
|
||||
it("sets the escorted ship as critical in battles", function () {
|
||||
let universe = new Universe();
|
||||
let fleet = new Fleet();
|
||||
let ship1 = fleet.addShip();
|
||||
let ship2 = fleet.addShip();
|
||||
let ship = new Ship();
|
||||
let destination = new StarLocation(new Star());
|
||||
let part = new MissionPartEscort(new Mission(universe, fleet), destination, ship);
|
||||
|
||||
part.onStarted();
|
||||
expect(fleet.ships).toContain(ship);
|
||||
|
||||
let enemy = new Fleet();
|
||||
enemy.addShip();
|
||||
let battle = new Battle(fleet, enemy);
|
||||
battle.start();
|
||||
battle.checkEndBattle();
|
||||
expect(battle.ended).toBe(false);
|
||||
|
||||
// if a fleet member dies, it is not over
|
||||
ship1.setDead();
|
||||
battle.checkEndBattle();
|
||||
expect(battle.ended).toBe(false);
|
||||
|
||||
// if the critical ship dies, it is defeat
|
||||
ship.setDead();
|
||||
battle.checkEndBattle();
|
||||
expect(battle.ended).toBe(true);
|
||||
expect(battle.outcome.winner).not.toBe(fleet);
|
||||
})
|
||||
})
|
||||
}
|
29
src/core/missions/MissionPartEscort.ts
Normal file
29
src/core/missions/MissionPartEscort.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
/// <reference path="MissionPartGoTo.ts" />
|
||||
|
||||
module TS.SpaceTac {
|
||||
/**
|
||||
* A mission part that requires the fleet to escort a specific ship to a destination
|
||||
*/
|
||||
export class MissionPartEscort extends MissionPartGoTo {
|
||||
ship: Ship
|
||||
|
||||
constructor(mission: Mission, destination: StarLocation, ship: Ship, directive?: string) {
|
||||
super(mission, destination, directive || `Escort ${ship.name} to ${destination.star.name} system`);
|
||||
|
||||
this.ship = ship;
|
||||
}
|
||||
|
||||
checkCompleted(): boolean {
|
||||
return super.checkCompleted() && contains(this.fleet.ships, this.ship);
|
||||
}
|
||||
|
||||
onStarted(): void {
|
||||
this.ship.critical = true;
|
||||
this.fleet.addShip(this.ship);
|
||||
}
|
||||
|
||||
onEnded(): void {
|
||||
this.fleet.removeShip(this.ship);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,9 +6,9 @@ module TS.SpaceTac.Specs {
|
|||
|
||||
let universe = new Universe();
|
||||
let fleet = new Fleet();
|
||||
let part = new MissionPartGoTo(new Mission(universe, fleet), destination, "Collect gems");
|
||||
let part = new MissionPartGoTo(new Mission(universe, fleet), destination);
|
||||
|
||||
expect(part.title).toEqual("Collect gems in Atanax system");
|
||||
expect(part.title).toEqual("Go to Atanax system");
|
||||
expect(part.checkCompleted()).toBe(false, "Init location");
|
||||
|
||||
fleet.setLocation(destination, true);
|
||||
|
@ -32,6 +32,7 @@ module TS.SpaceTac.Specs {
|
|||
let fleet = new Fleet();
|
||||
let part = new MissionPartGoTo(new Mission(universe, fleet), destination, "Investigate");
|
||||
|
||||
expect(part.title).toEqual("Investigate");
|
||||
expect(part.checkCompleted()).toBe(false);
|
||||
part.forceComplete();
|
||||
expect(part.checkCompleted()).toBe(true);
|
||||
|
|
|
@ -7,8 +7,8 @@ module TS.SpaceTac {
|
|||
export class MissionPartGoTo extends MissionPart {
|
||||
destination: StarLocation
|
||||
|
||||
constructor(mission: Mission, destination: StarLocation, directive: string, hint = true) {
|
||||
super(mission, hint ? `${directive} in ${destination.star.name} system` : directive);
|
||||
constructor(mission: Mission, destination: StarLocation, directive?: string) {
|
||||
super(mission, directive || `Go to ${destination.star.name} system`);
|
||||
|
||||
this.destination = destination;
|
||||
}
|
||||
|
|
|
@ -201,6 +201,9 @@ module TS.SpaceTac.UI {
|
|||
this.credits.setText(fleet.credits.toString());
|
||||
|
||||
this.portraits.scale.set(980 * this.portraits.scale.x / this.portraits.height, 980 * this.portraits.scale.y / this.portraits.height);
|
||||
if (this.portraits.width > 308) {
|
||||
this.portraits.scale.set(308 * this.portraits.scale.x / this.portraits.width, 308 * this.portraits.scale.y / this.portraits.width);
|
||||
}
|
||||
this.portraits.y = 80 + 160 * this.portraits.scale.x;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue