diff --git a/TODO.md b/TODO.md index fd57971..1578281 100644 --- a/TODO.md +++ b/TODO.md @@ -36,6 +36,7 @@ Character sheet Battle ------ +* Fix numerous effects being displayed on ships at the end, behind outcome dialog * 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) diff --git a/src/core/Shop.ts b/src/core/Shop.ts index e094c8d..fcda904 100644 --- a/src/core/Shop.ts +++ b/src/core/Shop.ts @@ -107,7 +107,7 @@ module TS.SpaceTac { */ 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 generator = new MissionGenerator(around.star.universe, around, this.random); let mission = generator.generate(); this.missions.push(mission); } diff --git a/src/core/Star.ts b/src/core/Star.ts index 1e3f7e5..0c365f0 100644 --- a/src/core/Star.ts +++ b/src/core/Star.ts @@ -94,6 +94,7 @@ module TS.SpaceTac { */ addLocation(type: StarLocationType): StarLocation { let result = new StarLocation(this, type); + this.locations.push(result); return result; } diff --git a/src/core/StarLocation.ts b/src/core/StarLocation.ts index b5b07a9..a34b7ad 100644 --- a/src/core/StarLocation.ts +++ b/src/core/StarLocation.ts @@ -72,13 +72,7 @@ module TS.SpaceTac { this.encounter_gen = true; if (this.encounter_random.random() < 0.8) { - var fleet_generator = new FleetGenerator(this.encounter_random); - let variations: [number, number][] = [[this.star.level, 4], [this.star.level + 1, 3], [this.star.level + 2, 2]]; - if (this.star.level > 1) { - variations.push([this.star.level - 1, 5]); - } - let [level, enemies] = this.encounter_random.choice(variations); - this.encounter = fleet_generator.generate(level, new Player(this.star.universe, "Enemy"), enemies, true); + this.setupEncounter(); } } @@ -123,5 +117,20 @@ module TS.SpaceTac { this.encounter_gen = true; this.encounter = null; } + + /** + * Forces the setup of an encounter + */ + setupEncounter() { + this.encounter_gen = true; + + let fleet_generator = new FleetGenerator(this.encounter_random); + let variations: [number, number][] = [[this.star.level, 4], [this.star.level + 1, 3], [this.star.level + 2, 2]]; + if (this.star.level > 1) { + variations.push([this.star.level - 1, 5]); + } + let [level, enemies] = this.encounter_random.choice(variations); + this.encounter = fleet_generator.generate(level, new Player(this.star.universe, "Enemy"), enemies, true); + } } } diff --git a/src/core/missions/MissionGenerator.spec.ts b/src/core/missions/MissionGenerator.spec.ts index 25fc52c..bed9d22 100644 --- a/src/core/missions/MissionGenerator.spec.ts +++ b/src/core/missions/MissionGenerator.spec.ts @@ -6,19 +6,33 @@ module TS.SpaceTac.Specs { 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 generator = new MissionGenerator(universe, loc1); let mission = generator.generateEscort(); - expect(mission.title).toBe("Escort a ship to a level 3 system"); + expect(mission.title).toBe("Escort a ship to a level 2 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); + expect(escort.destination).toBe(loc2); + expect(escort.ship.level.get()).toBe(2); + }); + + it("generates location cleaning missions", () => { + let universe = new Universe(); + let star1 = universe.addStar(1); + let loc1 = star1.locations[0]; + let loc2 = star1.addLocation(StarLocationType.PLANET); + + let generator = new MissionGenerator(universe, loc1); + let mission = generator.generateCleanLocation(); + + expect(mission.title).toBe("Defeat a level 1 fleet in this system"); + expect(mission.parts.length).toBe(1); + expect(mission.parts[0] instanceof MissionPartCleanLocation).toBe(true); + let part = mission.parts[0]; + expect(part.destination).toBe(loc2); }); }); } diff --git a/src/core/missions/MissionGenerator.ts b/src/core/missions/MissionGenerator.ts index 87bacb7..72bede1 100644 --- a/src/core/missions/MissionGenerator.ts +++ b/src/core/missions/MissionGenerator.ts @@ -19,13 +19,11 @@ module TS.SpaceTac { */ export class MissionGenerator { universe: Universe - level: number around: StarLocation random: RandomGenerator - constructor(universe: Universe, level: number, around: StarLocation, random = RandomGenerator.global) { + constructor(universe: Universe, around: StarLocation, random = RandomGenerator.global) { this.universe = universe; - this.level = level; this.around = around; this.random = random; } @@ -35,7 +33,8 @@ module TS.SpaceTac { */ generate(): Mission { let generators = [ - bound(this, "generateEscort") + bound(this, "generateEscort"), + bound(this, "generateCleanLocation"), ]; let generator = this.random.choice(generators); @@ -47,9 +46,9 @@ module TS.SpaceTac { /** * Generate a new ship */ - private generateShip() { + private generateShip(level: number) { let generator = new ShipGenerator(this.random); - let result = generator.generate(this.level, null, true); + let result = generator.generate(level, null, true); result.name = `${this.random.choice(POOL_SHIP_NAMES)}-${this.random.randInt(10, 999)}`; return result; } @@ -59,12 +58,28 @@ module TS.SpaceTac { */ generateEscort(): Mission { let mission = new Mission(this.universe); - let ship = this.generateShip(); - let dest_star = minBy(this.around.star.getNeighbors(), star => Math.abs(star.level - this.level)); + let dest_star = this.random.choice(this.around.star.getNeighbors()); let destination = this.random.choice(dest_star.locations); + let ship = this.generateShip(dest_star.level); mission.addPart(new MissionPartEscort(mission, destination, ship)); mission.title = `Escort a ship to a level ${dest_star.level} system`; return mission; } + + /** + * Generate a clean location mission + */ + generateCleanLocation(): Mission { + let mission = new Mission(this.universe); + let dest_star = this.random.choice(this.around.star.getNeighbors().concat([this.around.star])); + let choices = dest_star.locations; + if (dest_star == this.around.star) { + choices = choices.filter(loc => loc != this.around); + } + let destination = this.random.choice(choices); + mission.addPart(new MissionPartCleanLocation(mission, destination)); + mission.title = `Defeat a level ${destination.star.level} fleet in ${(dest_star == this.around.star) ? "this" : "a nearby"} system`; + return mission; + } } } diff --git a/src/core/missions/MissionPartCleanLocation.spec.ts b/src/core/missions/MissionPartCleanLocation.spec.ts new file mode 100644 index 0000000..358e003 --- /dev/null +++ b/src/core/missions/MissionPartCleanLocation.spec.ts @@ -0,0 +1,25 @@ +module TS.SpaceTac.Specs { + describe("MissionPartEscort", () => { + it("completes when the fleet is at location, and the encounter is clean", function () { + let destination = new StarLocation(new Star(null, 0, 0, "Atanax")); + destination.clearEncounter(); + + let universe = new Universe(); + let fleet = new Fleet(); + let part = new MissionPartCleanLocation(new Mission(universe, fleet), destination); + + expect(part.title).toEqual("Clean a planet in Atanax system"); + expect(part.checkCompleted()).toBe(false, "Init location"); + + expect(destination.isClear()).toBe(true); + part.onStarted(); + expect(destination.isClear()).toBe(false); + + fleet.setLocation(destination, true); + expect(part.checkCompleted()).toBe(false, "Encounter not clear"); + + destination.clearEncounter(); + expect(part.checkCompleted()).toBe(true, "Encouter cleared"); + }) + }) +} diff --git a/src/core/missions/MissionPartCleanLocation.ts b/src/core/missions/MissionPartCleanLocation.ts new file mode 100644 index 0000000..f86276b --- /dev/null +++ b/src/core/missions/MissionPartCleanLocation.ts @@ -0,0 +1,22 @@ +/// + +module TS.SpaceTac { + /** + * A mission part that requires the fleet to clean a specific location of enemies + */ + export class MissionPartCleanLocation extends MissionPartGoTo { + ship: Ship + + constructor(mission: Mission, destination: StarLocation, directive?: string) { + super(mission, destination, directive || `Clean a ${StarLocationType[destination.type].toLowerCase()} in ${destination.star.name} system`); + } + + checkCompleted(): boolean { + return super.checkCompleted() && this.destination.isClear(); + } + + onStarted(): void { + this.destination.setupEncounter(); + } + } +}