2017-07-06 22:55:29 +00:00
|
|
|
module TS.SpaceTac {
|
2017-07-09 21:18:05 +00:00
|
|
|
const POOL_SHIP_NAMES = [
|
|
|
|
"Zert",
|
|
|
|
"Ob'tec",
|
|
|
|
"Paayk",
|
|
|
|
"Fen_amr",
|
|
|
|
"TempZst",
|
|
|
|
"croNt",
|
|
|
|
"Appn",
|
|
|
|
"Vertix",
|
|
|
|
"Opan-vel",
|
|
|
|
"Yz-aol",
|
|
|
|
"Arkant",
|
|
|
|
"PNX",
|
|
|
|
]
|
|
|
|
|
2017-07-06 22:55:29 +00:00
|
|
|
/**
|
|
|
|
* Random generator of secondary missions that can be taken from
|
|
|
|
*/
|
|
|
|
export class MissionGenerator {
|
|
|
|
universe: Universe
|
|
|
|
around: StarLocation
|
|
|
|
random: RandomGenerator
|
2017-07-10 22:50:38 +00:00
|
|
|
equipment_generator: LootGenerator
|
2017-07-06 22:55:29 +00:00
|
|
|
|
2017-07-10 20:40:22 +00:00
|
|
|
constructor(universe: Universe, around: StarLocation, random = RandomGenerator.global) {
|
2017-07-06 22:55:29 +00:00
|
|
|
this.universe = universe;
|
|
|
|
this.around = around;
|
|
|
|
this.random = random;
|
2017-07-10 22:50:38 +00:00
|
|
|
this.equipment_generator = new LootGenerator(this.random);
|
2017-07-06 22:55:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate a single mission
|
|
|
|
*/
|
|
|
|
generate(): Mission {
|
|
|
|
let generators = [
|
2017-07-10 20:40:22 +00:00
|
|
|
bound(this, "generateEscort"),
|
|
|
|
bound(this, "generateCleanLocation"),
|
2017-07-06 22:55:29 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
let generator = this.random.choice(generators);
|
|
|
|
let result = generator();
|
2017-07-10 22:50:38 +00:00
|
|
|
if (result.value) {
|
|
|
|
result.reward = this.generateReward(result.value);
|
|
|
|
}
|
2017-07-06 22:55:29 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-07-09 21:18:05 +00:00
|
|
|
/**
|
2017-07-10 22:50:38 +00:00
|
|
|
* Generate a new ship that may be used in a mission
|
2017-07-09 21:18:05 +00:00
|
|
|
*/
|
2017-07-10 22:50:38 +00:00
|
|
|
generateShip(level: number) {
|
2017-07-09 21:18:05 +00:00
|
|
|
let generator = new ShipGenerator(this.random);
|
2017-07-10 20:40:22 +00:00
|
|
|
let result = generator.generate(level, null, true);
|
2017-07-09 21:18:05 +00:00
|
|
|
result.name = `${this.random.choice(POOL_SHIP_NAMES)}-${this.random.randInt(10, 999)}`;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-07-10 22:50:38 +00:00
|
|
|
/**
|
|
|
|
* Try to generate an equipment of given value
|
|
|
|
*/
|
|
|
|
tryGenerateEquipmentReward(value: number): Equipment | null {
|
|
|
|
let minvalue = value * 0.8;
|
|
|
|
let maxvalue = value * 1.2;
|
|
|
|
let qualities = [EquipmentQuality.FINE, EquipmentQuality.PREMIUM, EquipmentQuality.LEGENDARY];
|
|
|
|
|
|
|
|
let candidates: Equipment[] = [];
|
|
|
|
for (let pass = 0; pass < 10; pass++) {
|
|
|
|
let equipment: Equipment | null;
|
|
|
|
let level = 1;
|
|
|
|
do {
|
|
|
|
let quality = qualities[this.random.weighted([15, 12, 2])];
|
|
|
|
equipment = this.equipment_generator.generate(level, quality);
|
|
|
|
if (equipment && equipment.getPrice() >= minvalue && equipment.getPrice() <= maxvalue) {
|
|
|
|
candidates.push(equipment);
|
|
|
|
}
|
|
|
|
level += 1;
|
|
|
|
} while (equipment && equipment.getPrice() < maxvalue * 1.5 && level < 20);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (candidates.length > 0) {
|
|
|
|
return this.random.choice(candidates);
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate a reward
|
|
|
|
*/
|
|
|
|
generateReward(value: number): MissionReward {
|
|
|
|
if (this.random.bool()) {
|
|
|
|
let equipment = this.tryGenerateEquipmentReward(value);
|
|
|
|
if (equipment) {
|
|
|
|
return equipment;
|
|
|
|
} else {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper to set the difficulty of a mission
|
|
|
|
*/
|
|
|
|
setDifficulty(mission: Mission, base_value: number, fight_level: number) {
|
|
|
|
let level_diff = fight_level - this.around.star.level;
|
|
|
|
let code = (level_diff > 0) ? MissionDifficulty.hard : (level_diff < 0 ? MissionDifficulty.easy : MissionDifficulty.normal);
|
|
|
|
let value = fight_level * (base_value + base_value * 0.1 * clamp(level_diff, -5, 5));
|
|
|
|
mission.setDifficulty(code, Math.round(value));
|
|
|
|
}
|
|
|
|
|
2017-07-06 22:55:29 +00:00
|
|
|
/**
|
|
|
|
* Generate an escort mission
|
|
|
|
*/
|
|
|
|
generateEscort(): Mission {
|
|
|
|
let mission = new Mission(this.universe);
|
2017-07-10 20:40:22 +00:00
|
|
|
let dest_star = this.random.choice(this.around.star.getNeighbors());
|
2017-07-06 22:55:29 +00:00
|
|
|
let destination = this.random.choice(dest_star.locations);
|
2017-07-10 20:40:22 +00:00
|
|
|
let ship = this.generateShip(dest_star.level);
|
2017-07-06 22:55:29 +00:00
|
|
|
mission.addPart(new MissionPartEscort(mission, destination, ship));
|
|
|
|
mission.title = `Escort a ship to a level ${dest_star.level} system`;
|
2017-07-10 22:50:38 +00:00
|
|
|
this.setDifficulty(mission, 1000, dest_star.level);
|
2017-07-06 22:55:29 +00:00
|
|
|
return mission;
|
|
|
|
}
|
2017-07-10 20:40:22 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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]));
|
2017-07-10 22:50:38 +00:00
|
|
|
let here = (dest_star == this.around.star);
|
2017-07-10 20:40:22 +00:00
|
|
|
let choices = dest_star.locations;
|
2017-07-10 22:50:38 +00:00
|
|
|
if (here) {
|
2017-07-10 20:40:22 +00:00
|
|
|
choices = choices.filter(loc => loc != this.around);
|
|
|
|
}
|
|
|
|
let destination = this.random.choice(choices);
|
|
|
|
mission.addPart(new MissionPartCleanLocation(mission, destination));
|
2017-07-10 22:50:38 +00:00
|
|
|
mission.addPart(new MissionPartGoTo(mission, this.around, "Go back to collect your reward"));
|
|
|
|
mission.title = `Defeat a level ${destination.star.level} fleet in ${here ? "this" : "a nearby"} system`;
|
|
|
|
this.setDifficulty(mission, here ? 300 : 500, dest_star.level);
|
2017-07-10 20:40:22 +00:00
|
|
|
return mission;
|
|
|
|
}
|
2017-07-06 22:55:29 +00:00
|
|
|
}
|
|
|
|
}
|