161 lines
6.3 KiB
TypeScript
161 lines
6.3 KiB
TypeScript
module TK.SpaceTac {
|
|
// unit testing utilities
|
|
export class TestTools {
|
|
|
|
// Create a battle between two fleets, with a fixed play order (owned ships, then enemy ships)
|
|
static createBattle(own_ships = 1, enemy_ships = 1): Battle {
|
|
var fleet1 = new Fleet(new Player(undefined, "Attacker"));
|
|
var fleet2 = new Fleet(new Player(undefined, "Defender"));
|
|
|
|
while (own_ships--) {
|
|
fleet1.addShip();
|
|
}
|
|
while (enemy_ships--) {
|
|
fleet2.addShip();
|
|
}
|
|
|
|
var battle = new Battle(fleet1, fleet2);
|
|
battle.ships.list().forEach(ship => TestTools.setShipHP(ship, 1, 0));
|
|
battle.play_order = fleet1.ships.concat(fleet2.ships);
|
|
battle.setPlayingShip(battle.play_order[0]);
|
|
return battle;
|
|
}
|
|
|
|
// Get or add an equipment of a given slot type
|
|
static getOrGenEquipment(ship: Ship, slot: SlotType, template: LootTemplate, force_generate = false): Equipment {
|
|
var equipped = ship.listEquipment(slot);
|
|
var equipment: Equipment;
|
|
if (force_generate || equipped.length === 0) {
|
|
equipment = template.generate(1);
|
|
equipment.requirements = {};
|
|
ship.addSlot(slot).attach(equipment);
|
|
} else {
|
|
equipment = equipped[0];
|
|
}
|
|
|
|
return equipment;
|
|
}
|
|
|
|
/**
|
|
* Add an engine, allowing a ship to move *distance*, for each action points
|
|
*/
|
|
static addEngine(ship: Ship, distance: number): Equipment {
|
|
let equipment = ship.addSlot(SlotType.Engine).attach(new Equipment(SlotType.Engine));
|
|
equipment.action = new MoveAction(equipment, distance);
|
|
return equipment;
|
|
}
|
|
|
|
/**
|
|
* Add a weapon to a ship
|
|
*/
|
|
static addWeapon(ship: Ship, damage = 100, power_usage = 1, max_distance = 100, blast = 0, angle = 0): Equipment {
|
|
var equipment = ship.addSlot(SlotType.Weapon).attach(new Equipment(SlotType.Weapon));
|
|
equipment.action = new TriggerAction(equipment, [new DamageEffect(damage)], power_usage, max_distance, blast, angle);
|
|
return equipment;
|
|
}
|
|
|
|
// Set the current playing ship
|
|
static setShipPlaying(battle: Battle, ship: Ship): void {
|
|
add(battle.play_order, ship);
|
|
battle.play_index = battle.play_order.indexOf(ship);
|
|
ship.playing = true;
|
|
}
|
|
|
|
// Set a ship action points, adding/updating an equipment if needed
|
|
static setShipAP(ship: Ship, points: number, recovery: number = 0): Equipment {
|
|
var equipment = this.getOrGenEquipment(ship, SlotType.Power, new Equipments.NuclearReactor());
|
|
|
|
equipment.effects.forEach(effect => {
|
|
if (effect instanceof AttributeEffect) {
|
|
if (effect.attrcode === "power_capacity") {
|
|
effect.value = points;
|
|
} else if (effect.attrcode === "power_generation") {
|
|
effect.value = recovery;
|
|
}
|
|
}
|
|
});
|
|
|
|
ship.updateAttributes();
|
|
ship.setValue("power", points);
|
|
|
|
return equipment;
|
|
}
|
|
|
|
// Set a ship hull and shield points, adding/updating an equipment if needed
|
|
static setShipHP(ship: Ship, hull_points: number, shield_points: number): [Equipment, Equipment] {
|
|
var hull = TestTools.getOrGenEquipment(ship, SlotType.Hull, new Equipments.IronHull());
|
|
var shield = TestTools.getOrGenEquipment(ship, SlotType.Shield, new Equipments.ForceField());
|
|
|
|
hull.effects.forEach(effect => {
|
|
if (effect instanceof AttributeEffect) {
|
|
if (effect.attrcode === "hull_capacity") {
|
|
effect.value = hull_points;
|
|
}
|
|
}
|
|
});
|
|
shield.effects.forEach((effect: BaseEffect) => {
|
|
if (effect instanceof AttributeEffect) {
|
|
if (effect.attrcode === "shield_capacity") {
|
|
effect.value = shield_points;
|
|
}
|
|
}
|
|
});
|
|
|
|
ship.updateAttributes();
|
|
ship.restoreHealth();
|
|
|
|
return [hull, shield];
|
|
}
|
|
|
|
/**
|
|
* Force a ship attribute to a given value
|
|
*/
|
|
static setAttribute(ship: Ship, name: keyof ShipAttributes, value: number): void {
|
|
let attr = ship.attributes[name];
|
|
attr.reset();
|
|
attr.addModifier(value);
|
|
}
|
|
|
|
/**
|
|
* Check a diff chain on a given battle
|
|
*
|
|
* This will apply all diffs, then reverts them, checking at each step the battle state
|
|
*/
|
|
static diffChain(check: TestContext, battle: Battle, diffs: BaseBattleDiff[], checks: ((check: TestContext) => void)[]): void {
|
|
checks[0](check.sub("initial state"));
|
|
|
|
for (let i = 0; i < diffs.length; i++) {
|
|
diffs[i].apply(battle);
|
|
checks[i + 1](check.sub(`after diff ${i + 1} applied`));
|
|
}
|
|
|
|
for (let i = diffs.length - 1; i >= 0; i--) {
|
|
diffs[i].revert(battle);
|
|
checks[i](check.sub(`after diff ${i + 1} reverted`));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check an action chain on a given battle
|
|
*
|
|
* This will apply all actions, then reverts them, checking at each step the battle state
|
|
*/
|
|
static actionChain(check: TestContext, battle: Battle, actions: [Ship, BaseAction, Target | undefined][], checks: ((check: TestContext) => void)[]): void {
|
|
checks[0](check.sub("initial state"));
|
|
|
|
for (let i = 0; i < actions.length; i++) {
|
|
let [ship, action, target] = actions[i];
|
|
battle.setPlayingShip(ship);
|
|
let result = battle.applyOneAction(action.id, target);
|
|
check.equals(result, true, `action ${i + 1} successfully applied`);
|
|
checks[i + 1](check.sub(`after action ${i + 1} applied`));
|
|
}
|
|
|
|
for (let i = actions.length - 1; i >= 0; i--) {
|
|
battle.revertOneAction();
|
|
checks[i](check.sub(`after action ${i + 1} reverted`));
|
|
}
|
|
}
|
|
}
|
|
}
|