1
0
Fork 0

Fixed display when an escorted ship is added to the fleet

This commit is contained in:
Michaël Lemaire 2017-07-09 23:18:05 +02:00
parent ddb1152765
commit c8c08dc4cd
15 changed files with 235 additions and 37 deletions

19
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,19 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Run game in Chrome",
"type": "chrome",
"request": "launch",
"url": "http://localhost:8012",
"webRoot": "${workspaceRoot}/out"
},
{
"name": "Run tests in Chrome",
"type": "chrome",
"request": "launch",
"url": "http://localhost:8012/tests.html",
"webRoot": "${workspaceRoot}/out"
}
]
}

View File

@ -14,10 +14,11 @@ Map/story
* 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
* Fix galaxy generator sometimes being short on systems to create a proper level gradient (mainly in unit testing)
* Add ship personality (with icons to identify ?), with reaction dialogs
* Add factions and reputation
* Add generated missions with rewards
* Allow to cancel secondary missions
* Forbid to end up with more than 5 ships in the fleet because of escorts
* Show missions' destination near systems/locations
Character sheet
@ -29,7 +30,6 @@ Character sheet
* 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

View File

@ -48,17 +48,21 @@ module TS.SpaceTac {
return result;
}
// Pick a random model in the default collection
static getRandomModel(level: Number, random: RandomGenerator = new RandomGenerator()): ShipModel {
var collection = this.getDefaultCollection();
collection = collection.filter((model: ShipModel) => {
return model.level <= level;
});
var result = random.choice(collection);
if (!result) {
console.error("Couldn't pick a random model for level " + level.toString());
/**
* Pick a random model in the default collection
*/
static getRandomModel(level?: number, random: RandomGenerator = new RandomGenerator()): ShipModel {
let collection = this.getDefaultCollection();
if (level) {
collection = collection.filter(model => model.level <= level);
}
if (collection.length == 0) {
console.error("Couldn't pick a random model");
return new ShipModel("undefined", "Undefined");
} else {
return random.choice(collection);
}
return result;
}
}
}

View File

@ -121,10 +121,13 @@ module TS.SpaceTac {
* 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;
if (contains(this.missions, mission)) {
if (player.missions.addSecondary(mission, player.fleet)) {
remove(this.missions, mission);
return true;
} else {
return false;
}
} else {
return false;
}

View File

@ -212,7 +212,11 @@ module TS.SpaceTac {
// Choose two systems to be the lowest and highest danger zones (not connected directly)
let lowest = this.random.choice(this.stars.filter(star => star.getLinks().length > 1));
let highest = this.random.choice(this.stars.filter(star => star != lowest && !star.getLinkTo(lowest)));
let highest_choices = this.stars.filter(star => star != lowest && !star.getLinkTo(lowest));
if (highest_choices.length == 0) {
highest_choices = this.stars.filter(star => star != lowest);
}
let highest = this.random.choice(highest_choices);
highest.level = maximal;
// Make danger gradients

View File

@ -55,5 +55,45 @@ module TS.SpaceTac.Specs {
]);
expect(missions.main).toBeNull();
})
it("builds a hash to help monitor status changes", function () {
let universe = new Universe();
universe.generate(4);
let fleet = new Fleet();
fleet.setLocation(universe.getStartLocation(), true);
let missions = new ActiveMissions();
let hash = missions.getHash();
function checkChanged(info: string, expected = true) {
let new_hash = missions.getHash();
expect(new_hash != hash).toBe(expected, info);
hash = new_hash;
expect(missions.getHash()).toEqual(hash, "Stable after " + info);
}
checkChanged("Stable at init", false);
missions.startMainStory(universe, fleet);
checkChanged("Main story started");
let mission = new Mission(universe, fleet);
mission.addPart(new MissionPartConversation(mission, [new Ship()]));
mission.addPart(new MissionPartConversation(mission, [new Ship()]));
missions.addSecondary(mission, fleet);
checkChanged("Secondary mission accepted");
expect(mission.getIndex()).toBe(0);
missions.checkStatus();
expect(mission.getIndex()).toBe(1);
checkChanged("First conversation ended");
expect(missions.secondary.length).toBe(1);
missions.checkStatus();
expect(missions.secondary.length).toBe(0);
checkChanged("Second conversation ended - mission removed");
nn(missions.main).current_part.forceComplete();
missions.checkStatus();
checkChanged("Main mission progress");
});
})
}

View File

@ -5,15 +5,30 @@ module TS.SpaceTac {
export class ActiveMissions {
main: Mission | null = null
secondary: Mission[] = []
constructor() {
}
nextid = 2
/**
* Start the main story arc
*/
startMainStory(universe: Universe, fleet: Fleet) {
this.main = new MainStory(universe, fleet);
this.main.setStarted(1);
}
/**
* Add a secondary mission to the pool
*
* Returns true on success
*/
addSecondary(mission: Mission, fleet: Fleet): boolean {
if (!mission.main && this.secondary.length < 2) {
mission.fleet = fleet;
this.secondary.push(mission);
mission.setStarted(this.nextid++);
return true;
} else {
return false;
}
}
/**
@ -40,5 +55,12 @@ module TS.SpaceTac {
}
this.secondary = this.secondary.filter(mission => mission.checkStatus());
}
/**
* Get a hash that will change when any active mission changes status
*/
getHash(): number {
return sum(this.getCurrent().map(mission => mission.id * 10000 + mission.getIndex()));
}
}
}

View File

@ -24,6 +24,9 @@ module TS.SpaceTac {
// Title of this mission (should be kept short)
title: string
// Numerical identifier
id = -1
constructor(universe: Universe, fleet = new Fleet(), main = false) {
this.universe = universe;
this.fleet = fleet;
@ -48,6 +51,25 @@ module TS.SpaceTac {
return part;
}
/**
* Get the index of current part
*/
getIndex(): number {
return this.parts.indexOf(this.current_part);
}
/**
* Set the mission as started (start the first part)
*/
setStarted(id: number): void {
if (this.id < 0) {
this.id = id;
if (this.current_part) {
this.current_part.onStarted();
}
}
}
/**
* Check the status for current part, and move on to next part if necessary.
*
@ -59,7 +81,7 @@ module TS.SpaceTac {
} else if (this.current_part.checkCompleted()) {
this.current_part.onEnded();
let current_index = this.parts.indexOf(this.current_part);
let current_index = this.getIndex();
if (current_index < 0 || current_index >= this.parts.length - 1) {
this.completed = true;
return false;

View File

@ -1,4 +1,19 @@
module TS.SpaceTac {
const POOL_SHIP_NAMES = [
"Zert",
"Ob'tec",
"Paayk",
"Fen_amr",
"TempZst",
"croNt",
"Appn",
"Vertix",
"Opan-vel",
"Yz-aol",
"Arkant",
"PNX",
]
/**
* Random generator of secondary missions that can be taken from
*/
@ -29,12 +44,22 @@ module TS.SpaceTac {
return result;
}
/**
* Generate a new ship
*/
private generateShip() {
let generator = new ShipGenerator(this.random);
let result = generator.generate(this.level, null, true);
result.name = `${this.random.choice(POOL_SHIP_NAMES)}-${this.random.randInt(10, 999)}`;
return result;
}
/**
* Generate an escort mission
*/
generateEscort(): Mission {
let mission = new Mission(this.universe);
let ship = new Ship();
let ship = this.generateShip();
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));

View File

@ -14,7 +14,7 @@ module TS.SpaceTac.UI.Specs {
mission.addPart(new MissionPart(mission, "Get back to base"));
missions.secondary = [mission];
display.update();
display.checkUpdate();
expect(container.children.length).toBe(2);
expect(container.children[0] instanceof Phaser.Image).toBe(true);
checkText(container.children[1], "Get back to base");

View File

@ -6,18 +6,34 @@ module TS.SpaceTac.UI {
*/
export class ActiveMissionsDisplay extends UIComponent {
private missions: ActiveMissions
private hash: number
constructor(parent: BaseView, missions: ActiveMissions) {
super(parent, 520, 240);
this.missions = missions;
this.hash = missions.getHash();
this.update();
}
/**
* Check if the active missions' status changed
*/
checkUpdate(): boolean {
let new_hash = this.missions.getHash();
if (new_hash != this.hash) {
this.hash = new_hash;
this.update();
return true;
} else {
return false;
}
}
/**
* Update the current missions list
*/
update() {
private update() {
this.clearContent();
let active = this.missions.getCurrent();

View File

@ -13,9 +13,10 @@ module TS.SpaceTac.UI {
* Group to display a fleet
*/
export class FleetDisplay extends Phaser.Group {
private map: UniverseMapView;
private fleet: Fleet;
private tween: Phaser.Tween;
private map: UniverseMapView
private fleet: Fleet
private tween: Phaser.Tween
private ship_count = 0
constructor(parent: UniverseMapView, fleet: Fleet) {
super(parent.game);
@ -23,12 +24,7 @@ module TS.SpaceTac.UI {
this.map = parent;
this.fleet = fleet;
fleet.ships.forEach((ship, index) => {
let offset = LOCATIONS[index];
let sprite = this.game.add.image(offset[0], offset[1] + 150, `ship-${ship.model.code}-sprite`, 0, this);
sprite.scale.set(64 / sprite.width);
sprite.anchor.set(0.5, 0.5);
});
this.updateShipSprites();
if (fleet.location) {
this.position.set(fleet.location.star.x + fleet.location.x, fleet.location.star.y + fleet.location.y);
@ -39,6 +35,23 @@ module TS.SpaceTac.UI {
this.loopOrbit();
}
/**
* Update the ship sprites
*/
updateShipSprites() {
if (this.ship_count != this.fleet.ships.length) {
this.removeAll(true);
this.fleet.ships.forEach((ship, index) => {
let offset = LOCATIONS[index];
let sprite = this.game.add.image(offset[0], offset[1] + 150, `ship-${ship.model.code}-sprite`, 0, this);
sprite.scale.set(64 / sprite.width);
sprite.anchor.set(0.5, 0.5);
});
this.ship_count = this.fleet.ships.length;
}
}
get location(): StarLocation {
return this.fleet.location || new StarLocation();
}

View File

@ -36,7 +36,7 @@ module TS.SpaceTac.UI {
if (location.shop) {
let shop = location.shop;
actions.push(["Go to dockyard", () => view.openShop()]);
actions.push(["Show jobs", () => new MissionsDialog(view, shop, view.player)]);
actions.push(["Show jobs", () => view.openMissions()]);
}
switch (location.type) {

View File

@ -6,13 +6,15 @@ module TS.SpaceTac.UI {
shop: Shop
player: Player
location: StarLocation
on_change: Function
constructor(view: BaseView, shop: Shop, player: Player) {
constructor(view: BaseView, shop: Shop, player: Player, on_change?: Function) {
super(view);
this.shop = shop;
this.player = player;
this.location = player.fleet.location || new StarLocation();
this.on_change = on_change || (() => null);
this.refresh();
}
@ -46,6 +48,7 @@ module TS.SpaceTac.UI {
this.addMission(offset, mission.title, "Reward: ???", 2, () => {
this.shop.acceptMission(mission, this.player);
this.refresh();
this.on_change();
});
offset += 110;
});

View File

@ -155,6 +155,19 @@ module TS.SpaceTac.UI {
*/
refresh() {
this.setZoom(this.zoom);
this.character_sheet.updateFleet(this.player.fleet);
this.player_fleet.updateShipSprites();
}
/**
* Check active missions.
*
* When any mission status changes, a refresh is triggered.
*/
checkMissionsUpdate() {
if (this.missions.checkUpdate()) {
this.refresh();
}
}
/**
@ -172,10 +185,12 @@ module TS.SpaceTac.UI {
this.actions.setFromLocation(this.player.fleet.location, this);
this.missions.update();
this.missions.checkUpdate();
this.conversation.updateFromMissions(this.player.missions, () => {
this.player.missions.checkStatus();
this.missions.update();
if (this.missions.checkUpdate()) {
this.refresh();
}
});
if (interactive) {
@ -279,6 +294,18 @@ module TS.SpaceTac.UI {
}
}
/**
* Open the missions dialog (job posting)
*
* This will only work if current location has a dockyard
*/
openMissions(): void {
let location = this.player.fleet.location;
if (this.interactive && location && location.shop) {
new MissionsDialog(this, location.shop, this.player, () => this.checkMissionsUpdate());
}
}
/**
* Move the fleet to another location
*/