1
0
Fork 0
spacetac/src/core/TestTools.ts

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`));
}
}
}
}