Fixed encounter generation matching star system level
This commit is contained in:
parent
8ba518270b
commit
f8c443f3c9
3
TODO
3
TODO
|
@ -4,7 +4,7 @@
|
|||
* Character sheet: improve eye-catching for shop and loot section
|
||||
* Character sheet: highlight allowed destinations during drag-and-drop
|
||||
* Add permanent effects to ship models to ease balancing
|
||||
* Ships should start battle in formation to force them to move
|
||||
* Find incentives to move from starting position
|
||||
* Fix targetting not resetting when using action shortcuts
|
||||
* Add battle statistics and/or critics in outcome dialog
|
||||
* Add battle experience
|
||||
|
@ -40,7 +40,6 @@
|
|||
* TacticalAI: add pauses to not play too quickly
|
||||
* TacticalAI: replace BullyAI
|
||||
* Map: restore fog of war
|
||||
* Map: a star system should have an average level
|
||||
* Map: add information on current star/location + information on hovered location
|
||||
* Map: generate random shops
|
||||
* Map: remove jump links that cross the radius of other systems
|
||||
|
|
|
@ -50,9 +50,9 @@ module TS.SpaceTac {
|
|||
}
|
||||
|
||||
// Create a quick random battle, for testing purposes
|
||||
static newQuickRandom(start = true): Battle {
|
||||
var player1 = Player.newQuickRandom("John");
|
||||
var player2 = Player.newQuickRandom("Carl");
|
||||
static newQuickRandom(start = true, level = 1): Battle {
|
||||
var player1 = Player.newQuickRandom("John", level, true);
|
||||
var player2 = Player.newQuickRandom("Carl", level, true);
|
||||
|
||||
var result = new Battle(player1.fleet, player2.fleet);
|
||||
if (start) {
|
||||
|
|
|
@ -15,32 +15,32 @@ module TS.SpaceTac.Specs {
|
|||
var equipment = new Equipment();
|
||||
var ship = new Ship();
|
||||
|
||||
expect(equipment.canBeEquipped(ship)).toBe(true);
|
||||
expect(equipment.canBeEquipped(ship.attributes)).toBe(true);
|
||||
|
||||
equipment.requirements["skill_time"] = 2;
|
||||
|
||||
expect(equipment.canBeEquipped(ship)).toBe(false);
|
||||
expect(equipment.canBeEquipped(ship.attributes)).toBe(false);
|
||||
|
||||
ship.attributes.skill_time.set(1);
|
||||
|
||||
expect(equipment.canBeEquipped(ship)).toBe(false);
|
||||
expect(equipment.canBeEquipped(ship.attributes)).toBe(false);
|
||||
|
||||
ship.attributes.skill_time.set(2);
|
||||
|
||||
expect(equipment.canBeEquipped(ship)).toBe(true);
|
||||
expect(equipment.canBeEquipped(ship.attributes)).toBe(true);
|
||||
|
||||
ship.attributes.skill_time.set(3);
|
||||
|
||||
expect(equipment.canBeEquipped(ship)).toBe(true);
|
||||
expect(equipment.canBeEquipped(ship.attributes)).toBe(true);
|
||||
|
||||
// Second requirement
|
||||
equipment.requirements["skill_material"] = 3;
|
||||
|
||||
expect(equipment.canBeEquipped(ship)).toBe(false);
|
||||
expect(equipment.canBeEquipped(ship.attributes)).toBe(false);
|
||||
|
||||
ship.attributes.skill_material.set(4);
|
||||
|
||||
expect(equipment.canBeEquipped(ship)).toBe(true);
|
||||
expect(equipment.canBeEquipped(ship.attributes)).toBe(true);
|
||||
});
|
||||
|
||||
it("generates a description of the effects", function () {
|
||||
|
|
|
@ -112,19 +112,19 @@ module TS.SpaceTac {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns true if the equipment can be equipped on a ship.
|
||||
* Returns true if the equipment can be equipped on a ship with given skills.
|
||||
*
|
||||
* This checks *requirements* against the ship skills.
|
||||
* This checks *requirements* against the skills.
|
||||
*
|
||||
* This does not check where the equipment currently is (except if is it already attached and should be detached first).
|
||||
*/
|
||||
canBeEquipped(ship: Ship): boolean {
|
||||
canBeEquipped(skills: ShipAttributes): boolean {
|
||||
if (this.attached_to) {
|
||||
return false;
|
||||
} else {
|
||||
var able = true;
|
||||
iteritems(this.requirements, (attr, minvalue) => {
|
||||
if (ship.getAttribute(<keyof ShipAttributes>attr) < minvalue) {
|
||||
if (skills[attr].get() < minvalue) {
|
||||
able = false;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -9,13 +9,13 @@ module TS.SpaceTac {
|
|||
}
|
||||
|
||||
// Generate a fleet of a given level
|
||||
generate(level: number, player?: Player, ship_count = 3): Fleet {
|
||||
generate(level: number, player?: Player, ship_count = 3, upgrade = false): Fleet {
|
||||
var fleet = new Fleet(player);
|
||||
var ship_generator = new ShipGenerator(this.random);
|
||||
|
||||
while (ship_count--) {
|
||||
var ship = ship_generator.generate(level);
|
||||
ship.name = "Ship " + ship_count.toString();
|
||||
var ship = ship_generator.generate(level, null, upgrade);
|
||||
ship.name = `${fleet.player.name}'s Level ${ship.level.get()} ${ship.model.name}`;
|
||||
fleet.addShip(ship);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,8 +31,6 @@ module TS.SpaceTac {
|
|||
this.templates = templates;
|
||||
}
|
||||
|
||||
// TODO Add generator from skills
|
||||
|
||||
// Generate a random equipment for a specific level
|
||||
// If slot is specified, it will generate an equipment for this slot type specifically
|
||||
// If no equipment could be generated from available templates, null is returned
|
||||
|
@ -48,5 +46,27 @@ module TS.SpaceTac {
|
|||
// Pick a random equipment
|
||||
return this.random.choice(equipments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random equipment of highest level, from a given set of skills
|
||||
*/
|
||||
generateHighest(skills: ShipSkills, quality = EquipmentQuality.COMMON, slot: SlotType | null = null): Equipment | null {
|
||||
let templates = this.templates.filter(template => slot == null || slot == template.slot);
|
||||
let candidates: Equipment[] = [];
|
||||
let level = 1;
|
||||
|
||||
templates.forEach(template => {
|
||||
let equipment = template.generateHighest(skills, quality, this.random);
|
||||
if (equipment && equipment.level >= level) {
|
||||
if (equipment.level > level) {
|
||||
candidates.splice(0);
|
||||
level = equipment.level;
|
||||
}
|
||||
candidates.push(equipment);
|
||||
}
|
||||
});
|
||||
|
||||
return (candidates.length == 0) ? null : this.random.choice(candidates);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -213,6 +213,26 @@ module TS.SpaceTac {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the highest equipment level, for a given set of skills
|
||||
*/
|
||||
generateHighest(skills: ShipSkills, quality = EquipmentQuality.COMMON, random = RandomGenerator.global): Equipment | null {
|
||||
let level = 1;
|
||||
let equipment: Equipment | null = null;
|
||||
let attributes = new ShipAttributes();
|
||||
keys(skills).forEach(skill => attributes[skill].set(skills[skill].get()));
|
||||
do {
|
||||
let nequipment = this.generate(level, quality, random);
|
||||
if (nequipment.canBeEquipped(attributes)) {
|
||||
equipment = nequipment;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
level += 1;
|
||||
} while (level < 100);
|
||||
return equipment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set skill requirements that will be added to each level of equipment.
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
module TS.SpaceTac {
|
||||
// One player (human or IA)
|
||||
export class Player {
|
||||
// Player's name
|
||||
name: string;
|
||||
|
||||
// Universe in which we are playing
|
||||
universe: Universe;
|
||||
|
||||
|
@ -11,33 +14,17 @@ module TS.SpaceTac {
|
|||
visited: StarLocation[] = [];
|
||||
|
||||
// Create a player, with an empty fleet
|
||||
constructor(universe: Universe = new Universe()) {
|
||||
constructor(universe: Universe = new Universe(), name = "Player") {
|
||||
this.universe = universe;
|
||||
this.name = name;
|
||||
this.fleet = new Fleet(this);
|
||||
}
|
||||
|
||||
// Create a quick random player, with a fleet, for testing purposes
|
||||
static newQuickRandom(name: String): Player {
|
||||
var player = new Player(new Universe());
|
||||
var ship: Ship;
|
||||
var ship_generator = new ShipGenerator();
|
||||
|
||||
ship = ship_generator.generate(1);
|
||||
ship.name = name + "'s First";
|
||||
player.fleet.addShip(ship);
|
||||
|
||||
ship = ship_generator.generate(1);
|
||||
ship.name = name + "'s Second";
|
||||
player.fleet.addShip(ship);
|
||||
|
||||
ship = ship_generator.generate(1);
|
||||
ship.name = name + "'s Third";
|
||||
player.fleet.addShip(ship);
|
||||
|
||||
ship = ship_generator.generate(1);
|
||||
ship.name = name + "'s Fourth";
|
||||
player.fleet.addShip(ship);
|
||||
|
||||
static newQuickRandom(name: string, level = 1, upgrade = false): Player {
|
||||
let player = new Player(new Universe(), name);
|
||||
let generator = new FleetGenerator();
|
||||
player.fleet = generator.generate(level, player, 4, upgrade);
|
||||
return player;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ module TS.SpaceTac {
|
|||
name: string
|
||||
|
||||
// Code of the ShipModel used to create it
|
||||
model: string
|
||||
model: ShipModel
|
||||
|
||||
// Flag indicating if the ship is alive
|
||||
alive: boolean
|
||||
|
@ -100,10 +100,9 @@ module TS.SpaceTac {
|
|||
play_priority = 0;
|
||||
|
||||
// Create a new ship inside a fleet
|
||||
constructor(fleet: Fleet | null = null, name = "Ship") {
|
||||
constructor(fleet: Fleet | null = null, name = "Ship", model = new ShipModel("default", "Default", 1, 0)) {
|
||||
this.fleet = fleet || new Fleet();
|
||||
this.name = name;
|
||||
this.model = "default";
|
||||
this.alive = true;
|
||||
this.sticky_effects = [];
|
||||
this.slots = [];
|
||||
|
@ -115,6 +114,10 @@ module TS.SpaceTac {
|
|||
if (fleet) {
|
||||
fleet.addShip(this);
|
||||
}
|
||||
|
||||
this.model = model;
|
||||
this.setCargoSpace(model.cargo);
|
||||
model.slots.forEach(slot => this.addSlot(slot));
|
||||
}
|
||||
|
||||
// Returns true if the ship is able to play
|
||||
|
@ -532,7 +535,7 @@ module TS.SpaceTac {
|
|||
canEquip(item: Equipment): Slot | null {
|
||||
let free_slot = first(this.slots, slot => slot.type == item.slot_type && !slot.attached);
|
||||
if (free_slot) {
|
||||
if (item.canBeEquipped(this)) {
|
||||
if (item.canBeEquipped(this.attributes)) {
|
||||
return free_slot;
|
||||
} else {
|
||||
return null;
|
||||
|
|
|
@ -2,9 +2,9 @@ module TS.SpaceTac.Specs {
|
|||
describe("ShipGenerator", function () {
|
||||
it("can use ship model", function () {
|
||||
var gen = new ShipGenerator();
|
||||
var model = new ShipModel("test", 1, 2, SlotType.Shield, SlotType.Weapon, SlotType.Weapon);
|
||||
var model = new ShipModel("test", "Test", 1, 2, SlotType.Shield, SlotType.Weapon, SlotType.Weapon);
|
||||
var ship = gen.generate(1, model);
|
||||
expect(ship.model).toBe("test");
|
||||
expect(ship.model).toBe(model);
|
||||
expect(ship.cargo_space).toBe(2);
|
||||
expect(ship.slots.length).toBe(3);
|
||||
expect(ship.slots[0].type).toBe(SlotType.Shield);
|
||||
|
|
|
@ -10,28 +10,29 @@ module TS.SpaceTac {
|
|||
|
||||
// Generate a ship of a given level
|
||||
// The ship will not be named, nor will be a member of any fleet
|
||||
generate(level: number, model: ShipModel | null = null): Ship {
|
||||
var result = new Ship();
|
||||
var loot = new LootGenerator(this.random);
|
||||
|
||||
generate(level: number, model: ShipModel | null = null, upgrade = false): Ship {
|
||||
if (!model) {
|
||||
// Get a random model
|
||||
model = ShipModel.getRandomModel(level, this.random);
|
||||
}
|
||||
|
||||
// Apply model
|
||||
result.model = model.code;
|
||||
result.setCargoSpace(model.cargo);
|
||||
model.slots.forEach((slot: SlotType) => {
|
||||
result.addSlot(slot);
|
||||
});
|
||||
var result = new Ship(null, undefined, model);
|
||||
var loot = new LootGenerator(this.random);
|
||||
|
||||
// Set all skills to 1 (to be able to use at least basic equipment)
|
||||
keys(result.skills).forEach(skill => result.upgradeSkill(skill));
|
||||
|
||||
// Level upgrade
|
||||
result.level.forceLevel(level);
|
||||
if (upgrade) {
|
||||
while (result.getAvailableUpgradePoints() > 0) {
|
||||
result.upgradeSkill(this.random.choice(keys(SHIP_SKILLS)));
|
||||
}
|
||||
}
|
||||
|
||||
// Fill equipment slots
|
||||
result.slots.forEach((slot: Slot) => {
|
||||
var equipment = loot.generate(level, EquipmentQuality.COMMON, slot.type);
|
||||
var equipment = loot.generateHighest(result.skills, EquipmentQuality.COMMON, slot.type);
|
||||
if (equipment) {
|
||||
slot.attach(equipment)
|
||||
if (slot.attached !== equipment) {
|
||||
|
|
|
@ -5,6 +5,9 @@ module TS.SpaceTac {
|
|||
// Code to identify the model
|
||||
code: string;
|
||||
|
||||
// Human-readable model name
|
||||
name: string;
|
||||
|
||||
// Minimal level to use this model
|
||||
level: number;
|
||||
|
||||
|
@ -14,8 +17,9 @@ module TS.SpaceTac {
|
|||
// Available slots
|
||||
slots: SlotType[];
|
||||
|
||||
constructor(code: string, level: number, cargo: number, ...slots: SlotType[]) {
|
||||
constructor(code: string, name: string, level: number, cargo: number, ...slots: SlotType[]) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
this.level = level;
|
||||
this.cargo = cargo;
|
||||
this.slots = slots;
|
||||
|
@ -26,12 +30,12 @@ module TS.SpaceTac {
|
|||
// TODO Store in cache
|
||||
var result: ShipModel[] = [];
|
||||
|
||||
result.push(new ShipModel("scout", 1, 2, SlotType.Hull, SlotType.Power, SlotType.Power, SlotType.Engine, SlotType.Weapon));
|
||||
result.push(new ShipModel("scout", "Scout", 1, 2, SlotType.Hull, SlotType.Power, SlotType.Power, SlotType.Engine, SlotType.Weapon));
|
||||
|
||||
result.push(new ShipModel("whirlwind", 1, 4, SlotType.Hull, SlotType.Shield, SlotType.Power, SlotType.Engine,
|
||||
result.push(new ShipModel("whirlwind", "Whirlwind", 1, 4, SlotType.Hull, SlotType.Shield, SlotType.Power, SlotType.Engine,
|
||||
SlotType.Weapon, SlotType.Weapon));
|
||||
|
||||
result.push(new ShipModel("tomahawk", 1, 6, SlotType.Hull, SlotType.Shield, SlotType.Power, SlotType.Engine, SlotType.Engine,
|
||||
result.push(new ShipModel("tomahawk", "Tomahawk", 1, 6, SlotType.Hull, SlotType.Shield, SlotType.Power, SlotType.Engine, SlotType.Engine,
|
||||
SlotType.Weapon));
|
||||
|
||||
return result;
|
||||
|
|
|
@ -28,7 +28,7 @@ module TS.SpaceTac {
|
|||
|
||||
// Attach an equipment in this slot
|
||||
attach(equipment: Equipment): Equipment {
|
||||
if (this.type === equipment.slot_type && equipment.canBeEquipped(this.ship)) {
|
||||
if (this.type === equipment.slot_type && equipment.canBeEquipped(this.ship.attributes)) {
|
||||
this.attached = equipment;
|
||||
equipment.attached_to = this;
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ module TS.SpaceTac {
|
|||
if (this.encounter_random.random() < 0.8) {
|
||||
var fleet_generator = new FleetGenerator(this.encounter_random);
|
||||
var ship_count = this.encounter_random.randInt(1, 5);
|
||||
this.encounter = fleet_generator.generate(this.star.level, undefined, ship_count);
|
||||
this.encounter = fleet_generator.generate(this.star.level, undefined, ship_count, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ module TS.SpaceTac.UI {
|
|||
this.enemy = this.ship.getPlayer() != this.battleview.player;
|
||||
|
||||
// Add ship sprite
|
||||
this.sprite = new Phaser.Button(this.game, 0, 0, "ship-" + ship.model + "-sprite");
|
||||
this.sprite = new Phaser.Button(this.game, 0, 0, "ship-" + ship.model.code + "-sprite");
|
||||
this.sprite.rotation = ship.arena_angle;
|
||||
this.sprite.anchor.set(0.5, 0.5);
|
||||
this.sprite.scale.set(64 / this.sprite.width);
|
||||
|
|
|
@ -38,7 +38,7 @@ module TS.SpaceTac.UI {
|
|||
this.active_effects = new Phaser.Group(this.game);
|
||||
this.addChild(this.active_effects);
|
||||
|
||||
this.layer_portrait = new Phaser.Image(this.game, 8, 8, "ship-" + ship.model + "-portrait", 0);
|
||||
this.layer_portrait = new Phaser.Image(this.game, 8, 8, "ship-" + ship.model.code + "-portrait", 0);
|
||||
this.layer_portrait.scale.set(0.3, 0.3);
|
||||
this.addChild(this.layer_portrait);
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ module TS.SpaceTac.UI {
|
|||
this.sheet = sheet;
|
||||
this.ship = ship;
|
||||
|
||||
let portrait_pic = new Phaser.Image(this.game, 0, 0, `ship-${ship.model}-portrait`);
|
||||
let portrait_pic = new Phaser.Image(this.game, 0, 0, `ship-${ship.model.code}-portrait`);
|
||||
portrait_pic.anchor.set(0.5, 0.5);
|
||||
this.addChild(portrait_pic);
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ module TS.SpaceTac.UI {
|
|||
|
||||
fleet.ships.forEach((ship, index) => {
|
||||
let offset = LOCATIONS[index];
|
||||
let sprite = this.game.add.image(offset[0], offset[1] + 150, `ship-${ship.model}-sprite`, 0, this);
|
||||
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);
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue