1
0
Fork 0

Added cone targetting

This commit is contained in:
Michaël Lemaire 2017-10-03 18:11:30 +02:00
parent 08e1b506b1
commit 1936cfef8d
40 changed files with 361 additions and 296 deletions

View file

@ -36,7 +36,7 @@
"typescript": "^2.5.3"
},
"dependencies": {
"jasmine-core": "^2.8.0",
"jasmine-core": "2.8.0",
"parse": "^1.9.2",
"phaser": "^2.6.2",
"phaser-plugin-scene-graph": "^1.0.4"

View file

@ -11,5 +11,5 @@ dir=$(dirname $0)
test -x "${dir}/.env/bin/nodeenv" || ( virtualenv -p python3 "${dir}/.env" && "${dir}/.env/bin/pip" install --upgrade nodeenv )
test -e "${dir}/.env/node/bin/activate" || "${dir}/.env/bin/nodeenv" --node=6.11.1 --force "${dir}/.env/node"
test -e "${dir}/.env/node/bin/yarn" || "${dir}/.env/node/bin/shim" "${dir}/.env/node/bin/npm" install -g yarn@0.27.5
test -e "${dir}/.env/node/bin/yarn" || "${dir}/.env/node/bin/shim" "${dir}/.env/node/bin/npm" install -g yarn@1.1.0
PATH="${dir}/.env/node/bin:${PATH}" yarn "$@"

View file

@ -1,8 +1,15 @@
module TK.SpaceTac.Specs {
describe("ArenaLocation", () => {
it("gets distance and angle between two locations", () => {
it("gets distance and angle between two locations", function () {
expect(arenaDistance({ x: 0, y: 0 }, { x: 1, y: 1 })).toBeCloseTo(Math.sqrt(2), 8);
expect(arenaAngle({ x: 0, y: 0 }, { x: 1, y: 1 })).toBeCloseTo(Math.PI / 4, 8);
});
})
it("gets an angular distance", function () {
expect(angularDistance(0.5, 1.5)).toBe(1.0);
expect(angularDistance(0.5, 1.5 + Math.PI * 6)).toBeCloseTo(1.0, 0.000001);
expect(angularDistance(0.5, -0.5)).toBe(-1.0);
expect(angularDistance(0.5, -0.3 - Math.PI * 4)).toBeCloseTo(-0.8, 0.000001);
})
});
}

View file

@ -52,16 +52,23 @@ module TK.SpaceTac {
}
/**
* Get the normalized angle between two locations
* Get the normalized angle (in radians) between two locations
*/
export function arenaAngle(loc1: IArenaLocation, loc2: IArenaLocation) {
export function arenaAngle(loc1: IArenaLocation, loc2: IArenaLocation): number {
return Math.atan2(loc2.y - loc1.y, loc2.x - loc1.x);
}
/**
* Get the "angular distance" between two angles in radians
*/
export function angularDistance(angle1: number, angle2: number): number {
return (angle2 - angle1) % (Math.PI * 2);
}
/**
* Get the normalized distance between two locations
*/
export function arenaDistance(loc1: IArenaLocation, loc2: IArenaLocation) {
export function arenaDistance(loc1: IArenaLocation, loc2: IArenaLocation): number {
let dx = loc2.x - loc1.x;
let dy = loc2.y - loc1.y;
return Math.sqrt(dx * dx + dy * dy);
@ -70,7 +77,7 @@ module TK.SpaceTac {
/**
* Check if a location is inside an area
*/
export function arenaInside(loc1: IArenaLocation, loc2: IArenaCircleArea, border_inclusive = true) {
export function arenaInside(loc1: IArenaLocation, loc2: IArenaCircleArea, border_inclusive = true): boolean {
let dist = arenaDistance(loc1, loc2);
return border_inclusive ? (dist <= loc2.radius) : (dist < loc2.radius);
}

View file

@ -47,9 +47,7 @@ module TK.SpaceTac.Specs {
let equipment = new Equipment();
expect(equipment.getEffectsDescription()).toEqual("does nothing");
let action = new FireWeaponAction(equipment, 1, 200, 0, [
new DamageEffect(50)
]);
let action = new TriggerAction(equipment, [new DamageEffect(50)], 1, 200, 0);
equipment.action = action;
expect(equipment.getEffectsDescription()).toEqual("Fire (power usage 1, max range 200km):\n• do 50 damage on target");

View file

@ -64,7 +64,7 @@ module TK.SpaceTac {
equipment.effects.forEach(effectFactor);
if (equipment.action instanceof FireWeaponAction) {
if (equipment.action instanceof TriggerAction) {
simpleFactor(equipment.action, 'power', true);
simpleFactor(equipment.action, 'blast');
simpleFactor(equipment.action, 'range');

View file

@ -95,15 +95,15 @@ module TK.SpaceTac.Specs {
it("adds fire actions", function () {
let template = new LootTemplate(SlotType.Weapon, "Weapon");
template.addFireAction(istep(1), istep(100), istep(50), [
template.addTriggerAction(istep(1), [
new EffectTemplate(new FakeEffect(3), { "fakevalue": istep(8) })
]);
], istep(100), istep(50), istep(10));
let result = template.generate(1);
expect(result.action).toEqual(new FireWeaponAction(result, 1, 100, 50, [new FakeEffect(8)]));
expect(result.action).toEqual(new TriggerAction(result, [new FakeEffect(8)], 1, 100, 50, 10));
result = template.generate(2);
expect(result.action).toEqual(new FireWeaponAction(result, 2, 101, 51, [new FakeEffect(9)]));
expect(result.action).toEqual(new TriggerAction(result, [new FakeEffect(9)], 2, 101, 51, 11));
});
it("adds drone actions", function () {
@ -126,10 +126,10 @@ module TK.SpaceTac.Specs {
template.addAttributeEffect("maneuvrability", irepeat(1));
expect(template.hasDamageEffect()).toBe(false);
template.addFireAction(irepeat(1), irepeat(50), irepeat(50), [new EffectTemplate(new BaseEffect("test"), {})]);
template.addTriggerAction(irepeat(1), [new EffectTemplate(new BaseEffect("test"), {})], irepeat(50), irepeat(50));
expect(template.hasDamageEffect()).toBe(false);
template.addFireAction(irepeat(1), irepeat(50), irepeat(50), [new EffectTemplate(new DamageEffect(20), {})]);
template.addTriggerAction(irepeat(1), [new EffectTemplate(new DamageEffect(20), {})], irepeat(50), irepeat(50));
expect(template.hasDamageEffect()).toBe(true);
});
});

View file

@ -203,12 +203,12 @@ module TK.SpaceTac {
}
/**
* Add a fire weapon action.
* Add a trigger action.
*/
addFireAction(power: LeveledValue, range: LeveledValue, blast: LeveledValue, effects: EffectTemplate<BaseEffect>[]): void {
addTriggerAction(power: LeveledValue, effects: EffectTemplate<BaseEffect>[], range: LeveledValue = irepeat(0), blast: LeveledValue = irepeat(0), angle: LeveledValue = irepeat(0)): void {
this.base_modifiers.push((equipment, level) => {
let reffects = effects.map(effect => effect.generate(level));
equipment.action = new FireWeaponAction(equipment, resolveForLevel(power, level), resolveForLevel(range, level), resolveForLevel(blast, level), reffects);
equipment.action = new TriggerAction(equipment, reffects, resolveForLevel(power, level), resolveForLevel(range, level), resolveForLevel(blast, level), resolveForLevel(angle, level));
});
}
@ -238,7 +238,7 @@ module TK.SpaceTac {
hasDamageEffect(): boolean {
let example = this.generate(1);
let action = example.action;
if (action instanceof FireWeaponAction || action instanceof DeployDroneAction) {
if (action instanceof TriggerAction || action instanceof DeployDroneAction) {
return any(action.effects, effect => effect instanceof DamageEffect || (effect instanceof StickyEffect && effect.base instanceof DamageEffect));
} else {
return false;

View file

@ -5,7 +5,7 @@ module TK.SpaceTac.Specs {
let ship = new Ship();
TestTools.setShipAP(ship, ship_ap);
TestTools.addEngine(ship, engine_distance);
let action = new FireWeaponAction(new Equipment(), weapon_ap, distance);
let action = new TriggerAction(new Equipment(), [], weapon_ap, distance);
let simulator = new MoveFireSimulator(ship);
return [ship, simulator, action];
}

View file

@ -115,7 +115,7 @@ module TK.SpaceTac.Specs {
slot = ship.addSlot(SlotType.Power);
equipment = new Equipment(slot.type);
equipment.action = new FireWeaponAction(equipment);
equipment.action = new TriggerAction(equipment);
slot.attach(equipment);
actions = ship.getAvailableActions();

View file

@ -436,7 +436,7 @@ module TK.SpaceTac {
let start = copy(this.location);
let area_effects = imaterialize(this.iToggleActions(true));
let old_impacted_ships = area_effects.map(action => action.getAffectedShips(this));
let old_impacted_ships = area_effects.map(action => action.getImpactedShips(this, Target.newFromShip(this)));
let old_area_effects = this.getActiveEffects().area;
if (engine) {
@ -450,7 +450,7 @@ module TK.SpaceTac {
this.addBattleEvent(new MoveEvent(this, start, copy(this.location), engine));
}
let new_impacted_ships = area_effects.map(action => action.getAffectedShips(this));
let new_impacted_ships = area_effects.map(action => action.getImpactedShips(this, Target.newFromShip(this)));
let diff_impacted_ships = flatten(zip(old_impacted_ships, new_impacted_ships).map(([a, b]) => disjunctunion(a, b)));
let new_area_effects = this.getActiveEffects().area;
if (disjunctunion(old_area_effects, new_area_effects).length > 0) {

View file

@ -47,9 +47,9 @@ module TK.SpaceTac {
/**
* Add a weapon to a ship
*/
static addWeapon(ship: Ship, damage = 100, power_usage = 1, max_distance = 100, blast = 0): Equipment {
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 FireWeaponAction(equipment, power_usage, max_distance, blast, [new DamageEffect(damage)], "Test Weapon");
equipment.action = new TriggerAction(equipment, [new DamageEffect(damage)], power_usage, max_distance, blast, angle, "Test Weapon");
return equipment;
}

View file

@ -82,24 +82,5 @@ module TK.SpaceTac {
expect(power.wear).toBe(1);
expect(equipment.wear).toBe(1);
})
it("guesses targetting mode", function () {
let ship = new Ship();
let action = new BaseAction("test", "Test");
expect(action.getTargettingMode(ship)).toEqual(ActionTargettingMode.SELF_CONFIRM);
action = new BaseAction("test", "Test");
spyOn(action, "getRangeRadius").and.returnValue(50);
expect(action.getTargettingMode(ship)).toEqual(ActionTargettingMode.SHIP);
action = new BaseAction("test", "Test");
spyOn(action, "getRangeRadius").and.returnValue(50);
spyOn(action, "getBlastRadius").and.returnValue(20);
expect(action.getTargettingMode(ship)).toEqual(ActionTargettingMode.SPACE);
action = new BaseAction("test", "Test");
spyOn(action, "getBlastRadius").and.returnValue(20);
expect(action.getTargettingMode(ship)).toEqual(ActionTargettingMode.SURROUNDINGS);
})
});
}

View file

@ -50,20 +50,7 @@ module TK.SpaceTac {
* Get the targetting mode
*/
getTargettingMode(ship: Ship): ActionTargettingMode {
let blast = this.getBlastRadius(ship);
let range = this.getRangeRadius(ship);
if (blast) {
if (range) {
return ActionTargettingMode.SPACE;
} else {
return ActionTargettingMode.SURROUNDINGS;
}
} else if (range) {
return ActionTargettingMode.SHIP;
} else {
return ActionTargettingMode.SELF_CONFIRM;
}
return ActionTargettingMode.SELF;
}
/**
@ -119,7 +106,11 @@ module TK.SpaceTac {
return null;
}
// Get the number of action points the action applied to a target would use
/**
* Get the number of action points the action applied to a target would use
*
* If target is null, an estimated cost is returned.
*/
getActionPointsUsage(ship: Ship, target: Target | null): number {
return 0;
}
@ -129,9 +120,25 @@ module TK.SpaceTac {
return 0;
}
// Get the effect area radius of this action
getBlastRadius(ship: Ship): number {
return 0;
/**
* Filter a list of ships to return only those impacted by this action
*
* This may be used as an indicator for helping the player in targetting, or to effectively apply the effects
*/
filterImpactedShips(source: IArenaLocation, target: Target, ships: Ship[]): Ship[] {
return [];
}
/**
* Get a list of ships impacted by this action
*/
getImpactedShips(ship: Ship, target: Target, source: IArenaLocation = ship.location): Ship[] {
let battle = ship.getBattle();
if (battle) {
return this.filterImpactedShips(source, target, imaterialize(battle.iships(true)));
} else {
return [];
}
}
/**

View file

@ -1,5 +1,3 @@
/// <reference path="../effects/BaseEffect.ts" />
module TK.SpaceTac {
describe("DeployDroneAction", function () {
it("stores useful information", function () {

View file

@ -33,6 +33,10 @@ module TK.SpaceTac {
this.effects = effects;
}
getTargettingMode(ship: Ship): ActionTargettingMode {
return ActionTargettingMode.SPACE;
}
getActionPointsUsage(ship: Ship, target: Target | null): number {
return this.power;
}
@ -41,8 +45,8 @@ module TK.SpaceTac {
return this.deploy_distance;
}
getBlastRadius(ship: Ship): number {
return this.effect_radius;
filterImpactedShips(source: ArenaLocation, target: Target, ships: Ship[]): Ship[] {
return ships.filter(ship => arenaDistance(ship.location, target) <= this.effect_radius);
}
checkLocationTarget(ship: Ship, target: Target): Target {

View file

@ -0,0 +1,31 @@
module TK.SpaceTac {
describe("ToggleAction", function () {
it("returns correct targetting mode", function () {
let action = new ToggleAction(new Equipment(), 1, 0, []);
expect(action.getTargettingMode(new Ship())).toBe(ActionTargettingMode.SELF_CONFIRM);
action.activated = true;
expect(action.getTargettingMode(new Ship())).toBe(ActionTargettingMode.SELF_CONFIRM);
action = new ToggleAction(new Equipment(), 1, 50, []);
expect(action.getTargettingMode(new Ship())).toBe(ActionTargettingMode.SURROUNDINGS);
action.activated = true;
expect(action.getTargettingMode(new Ship())).toBe(ActionTargettingMode.SELF_CONFIRM);
})
it("collects impacted ships", function () {
let action = new ToggleAction(new Equipment(), 1, 50, []);
let battle = new Battle();
let ship1 = battle.fleets[0].addShip();
ship1.setArenaPosition(0, 0);
let ship2 = battle.fleets[0].addShip();
ship2.setArenaPosition(0, 30);
let ship3 = battle.fleets[0].addShip();
ship3.setArenaPosition(0, 60);
let result = action.getImpactedShips(ship1, Target.newFromShip(ship1));
expect(result).toEqual([ship1, ship2]);
});
})
}

View file

@ -29,10 +29,10 @@ module TK.SpaceTac {
}
getTargettingMode(ship: Ship): ActionTargettingMode {
if (this.activated) {
return ActionTargettingMode.SELF;
if (this.activated || !this.radius) {
return ActionTargettingMode.SELF_CONFIRM;
} else {
return super.getTargettingMode(ship);
return ActionTargettingMode.SURROUNDINGS;
}
}
@ -44,30 +44,20 @@ module TK.SpaceTac {
return 0;
}
getBlastRadius(ship: Ship): number {
return this.radius;
filterImpactedShips(source: ArenaLocation, target: Target, ships: Ship[]): Ship[] {
return ships.filter(ship => arenaDistance(ship.location, source) <= this.radius);
}
checkShipTarget(ship: Ship, target: Target): Target | null {
return (ship == target.ship) ? target : null;
}
/**
* Get the list of ships in range to be affected
*/
getAffectedShips(ship: Ship): Ship[] {
let target = Target.newFromShip(ship);
let radius = this.getBlastRadius(ship);
let battle = ship.getBattle();
return (radius && battle) ? battle.collectShipsInCircle(target, radius, true) : ((target.ship && target.ship.alive) ? [target.ship] : []);
}
/**
* Collect the effects applied by this action
*/
getEffects(ship: Ship): [Ship, BaseEffect][] {
getEffects(ship: Ship, target: Target, source = ship.location): [Ship, BaseEffect][] {
let result: [Ship, BaseEffect][] = [];
let ships = this.getAffectedShips(ship);
let ships = this.getImpactedShips(ship, target, source);
ships.forEach(ship => {
this.effects.forEach(effect => result.push([ship, effect]));
});
@ -77,7 +67,7 @@ module TK.SpaceTac {
protected customApply(ship: Ship, target: Target) {
this.activated = !this.activated;
ship.addBattleEvent(new ToggleEvent(ship, this, this.activated));
this.getAffectedShips(ship).forEach(iship => iship.setActiveEffectsChanged());
this.getImpactedShips(ship, target).forEach(iship => iship.setActiveEffectsChanged());
}
getEffectsDescription(): string {

View file

@ -1,15 +1,13 @@
/// <reference path="../effects/BaseEffect.ts" />
module TK.SpaceTac {
describe("FireWeaponAction", function () {
describe("TriggerAction", function () {
it("constructs correctly", function () {
let equipment = new Equipment(SlotType.Weapon, "testweapon");
let action = new FireWeaponAction(equipment, 4, 30, 10);
let action = new TriggerAction(equipment, [], 4, 30, 10);
expect(action.code).toEqual("fire-testweapon");
expect(action.name).toEqual("Fire");
expect(action.equipment).toBe(equipment);
});
})
it("applies effects to alive ships in blast radius", function () {
let fleet = new Fleet();
@ -17,7 +15,7 @@ module TK.SpaceTac {
let equipment = new Equipment(SlotType.Weapon, "testweapon");
let effect = new BaseEffect("testeffect");
let mock_apply = spyOn(effect, "applyOnShip").and.stub();
let action = new FireWeaponAction(equipment, 5, 100, 10, [effect]);
let action = new TriggerAction(equipment, [effect], 5, 100, 10);
TestTools.setShipAP(ship, 10);
@ -37,7 +35,7 @@ module TK.SpaceTac {
action.apply(ship, Target.newFromLocation(50, 50));
expect(mock_apply).toHaveBeenCalledTimes(1);
expect(mock_apply).toHaveBeenCalledWith(ship2, ship);
});
})
it("transforms ship target in location target, when the weapon has blast radius", function () {
let ship1 = new Ship();
@ -62,7 +60,46 @@ module TK.SpaceTac {
target = action.checkTarget(ship1, Target.newFromShip(ship2));
expect(target).toEqual(new Target(100, 10));
});
})
it("lists impacted ships", function () {
let ship1 = new Ship(null, "S1");
ship1.setArenaPosition(10, 50);
let ship2 = new Ship(null, "S2");
ship2.setArenaPosition(40, 60);
let ship3 = new Ship(null, "S3");
ship3.setArenaPosition(0, 30);
let ships = [ship1, ship2, ship3];
let action = new TriggerAction(new Equipment(), [], 1, 50);
expect(action.filterImpactedShips({ x: 0, y: 0 }, Target.newFromShip(ship2), ships)).toEqual([ship2]);
expect(action.filterImpactedShips({ x: 0, y: 0 }, Target.newFromLocation(10, 50), ships)).toEqual([]);
action = new TriggerAction(new Equipment(), [], 1, 50, 40);
expect(action.filterImpactedShips({ x: 0, y: 0 }, Target.newFromLocation(20, 20), ships)).toEqual([ship1, ship3]);
action = new TriggerAction(new Equipment(), [], 1, 100, 0, 30);
expect(action.filterImpactedShips({ x: 0, y: 51 }, Target.newFromLocation(30, 50), ships)).toEqual([ship1, ship2]);
})
it("guesses targetting mode", function () {
let ship = new Ship();
let equ = new Equipment();
let action = new TriggerAction(equ, []);
expect(action.getTargettingMode(ship)).toEqual(ActionTargettingMode.SELF_CONFIRM, "self");
action = new TriggerAction(equ, [], 1, 50);
expect(action.getTargettingMode(ship)).toEqual(ActionTargettingMode.SHIP, "ship");
action = new TriggerAction(equ, [], 1, 50, 20);
expect(action.getTargettingMode(ship)).toEqual(ActionTargettingMode.SPACE, "blast");
action = new TriggerAction(equ, [], 1, 0, 20);
expect(action.getTargettingMode(ship)).toEqual(ActionTargettingMode.SURROUNDINGS, "surroundings");
action = new TriggerAction(equ, [], 1, 50, 0, 15);
expect(action.getTargettingMode(ship)).toEqual(ActionTargettingMode.SPACE, "angle");
})
it("rotates toward the target", function () {
let ship = new Ship();
@ -78,6 +115,6 @@ module TK.SpaceTac {
result = action.apply(ship, Target.newFromShip(ship));
expect(result).toBe(true);
expect(ship.arena_angle).toBeCloseTo(1.107, 0.001);
});
})
});
}

View file

@ -2,31 +2,35 @@
module TK.SpaceTac {
/**
* Action to fire a weapon on another ship, or in space
* Action to trigger an equipment (for example a weapon), with an optional target
*/
export class FireWeaponAction extends BaseAction {
export class TriggerAction extends BaseAction {
// Power consumption
power: number
// Maximal range of the weapon
// Maximal range of the weapon (distance to target)
range: number
// Blast radius
// Radius around the target that will be impacted
blast: number
// Angle of the area between the source and the target that will be impacted
angle: number
// Effects applied on target
effects: BaseEffect[]
// Equipment cannot be null
equipment: Equipment
constructor(equipment: Equipment, power = 1, range = 0, blast = 0, effects: BaseEffect[] = [], name = range ? "Fire" : "Trigger") {
constructor(equipment: Equipment, effects: BaseEffect[] = [], power = 1, range = 0, blast = 0, angle = 0, name = range ? "Fire" : "Trigger") {
super("fire-" + equipment.code, name, equipment);
this.power = power;
this.range = range;
this.effects = effects;
this.blast = blast;
this.angle = angle;
}
getDefaultTarget(ship: Ship): Target {
@ -46,6 +50,24 @@ module TK.SpaceTac {
}
}
getTargettingMode(ship: Ship): ActionTargettingMode {
if (this.blast) {
if (this.range) {
return ActionTargettingMode.SPACE;
} else {
return ActionTargettingMode.SURROUNDINGS;
}
} else if (this.range) {
if (this.angle) {
return ActionTargettingMode.SPACE;
} else {
return ActionTargettingMode.SHIP;
}
} else {
return ActionTargettingMode.SELF_CONFIRM;
}
}
getActionPointsUsage(ship: Ship, target: Target | null): number {
return this.power;
}
@ -54,12 +76,20 @@ module TK.SpaceTac {
return this.range;
}
getBlastRadius(ship: Ship): number {
return this.blast;
filterImpactedShips(source: ArenaLocation, target: Target, ships: Ship[]): Ship[] {
if (this.blast) {
return ships.filter(ship => arenaDistance(ship.location, target) <= this.blast);
} else if (this.angle) {
let angle = arenaAngle(source, target);
let maxangle = (this.angle * 0.5) * Math.PI / 180;
return ships.filter(ship => arenaDistance(source, ship.location) <= this.range && Math.abs(angularDistance(arenaAngle(source, ship.location), angle)) < maxangle);
} else {
return ships.filter(ship => target.ship === ship);
}
}
checkLocationTarget(ship: Ship, target: Target): Target | null {
if (target && this.blast > 0) {
if (target && (this.blast > 0 || this.angle > 0)) {
target = target.constraintInRange(ship.arena_x, ship.arena_y, this.range);
return target;
} else {
@ -73,7 +103,7 @@ module TK.SpaceTac {
return null;
} else {
// Check if target is in range
if (this.blast > 0) {
if (this.blast > 0 || this.angle > 0) {
return this.checkLocationTarget(ship, new Target(target.x, target.y));
} else if (target.isInRange(ship.arena_x, ship.arena_y, this.range)) {
return target;
@ -86,11 +116,9 @@ module TK.SpaceTac {
/**
* Collect the effects applied by this action
*/
getEffects(ship: Ship, target: Target): [Ship, BaseEffect][] {
getEffects(ship: Ship, target: Target, source = ship.location): [Ship, BaseEffect][] {
let result: [Ship, BaseEffect][] = [];
let blast = this.getBlastRadius(ship);
let battle = ship.getBattle();
let ships = (blast && battle) ? battle.collectShipsInCircle(target, blast, true) : ((target.ship && target.ship.alive) ? [target.ship] : []);
let ships = this.getImpactedShips(ship, target, source);
ships.forEach(ship => {
this.effects.forEach(effect => result.push([ship, effect]));
});
@ -126,7 +154,16 @@ module TK.SpaceTac {
let desc = `${this.name} (${info.join(", ")})`;
let effects = this.effects.map(effect => {
let suffix = this.blast ? `in ${this.blast}km radius` : (this.range ? "on target" : "on self");
let suffix: string;
if (this.blast) {
suffix = `in ${this.blast}km radius`;
} else if (this.angle) {
suffix = `in ${this.angle}° arc`;
} else if (this.range) {
suffix = "on target";
} else {
suffix = "on self";
}
return "• " + effect.getDescription() + " " + suffix;
});
return `${desc}:\n${effects.join("\n")}`;

View file

@ -78,7 +78,7 @@ module TK.SpaceTac {
let result: [Ship, BaseEffect][] = [];
// Effects of weapon
if (this.action instanceof FireWeaponAction) {
if (this.action instanceof TriggerAction) {
result = result.concat(this.action.getEffects(this.ship, this.target));
} else if (this.action instanceof DeployDroneAction) {
let ships = this.battle.collectShipsInCircle(this.target, this.action.effect_radius, true);

View file

@ -71,7 +71,7 @@ module TK.SpaceTac {
*/
static produceDirectShots(ship: Ship, battle: Battle): TacticalProducer {
let enemies = ifilter(battle.iships(), iship => iship.alive && iship.getPlayer() !== ship.getPlayer());
let weapons = ifilter(getPlayableActions(ship), action => action instanceof FireWeaponAction);
let weapons = ifilter(getPlayableActions(ship), action => action instanceof TriggerAction);
return imap(icombine(enemies, weapons), ([enemy, weapon]) => new Maneuver(ship, weapon, Target.newFromShip(enemy)));
}
@ -91,11 +91,11 @@ module TK.SpaceTac {
*/
static produceInterestingBlastShots(ship: Ship, battle: Battle): TacticalProducer {
// TODO Work with groups of 3, 4 ...
let weapons = ifilter(getPlayableActions(ship), action => action instanceof FireWeaponAction && action.blast > 0);
let weapons = <Iterator<TriggerAction>>ifilter(getPlayableActions(ship), action => action instanceof TriggerAction && action.blast > 0);
let enemies = battle.ienemies(ship.getPlayer(), true);
// FIXME This produces duplicates (x, y) and (y, x)
let couples = ifilter(icombine(enemies, enemies), ([e1, e2]) => e1 != e2);
let candidates = ifilter(icombine(weapons, couples), ([weapon, [e1, e2]]) => Target.newFromShip(e1).getDistanceTo(Target.newFromShip(e2)) < weapon.getBlastRadius(ship) * 2);
let candidates = ifilter(icombine(weapons, couples), ([weapon, [e1, e2]]) => Target.newFromShip(e1).getDistanceTo(Target.newFromShip(e2)) < weapon.blast * 2);
let result = imap(candidates, ([weapon, [e1, e2]]) => new Maneuver(ship, weapon, Target.newFromLocation((e1.arena_x + e2.arena_x) / 2, (e1.arena_y + e2.arena_y) / 2)));
return result;
}
@ -104,8 +104,8 @@ module TK.SpaceTac {
* Produce random blast weapon shots, on a grid.
*/
static produceRandomBlastShots(ship: Ship, battle: Battle): TacticalProducer {
let weapons = ifilter(getPlayableActions(ship), action => action instanceof FireWeaponAction && action.blast > 0);
let candidates = ifilter(icombine(weapons, scanArena(battle)), ([weapon, location]) => (<FireWeaponAction>weapon).getEffects(ship, location).length > 0);
let weapons = ifilter(getPlayableActions(ship), action => action instanceof TriggerAction && action.blast > 0);
let candidates = ifilter(icombine(weapons, scanArena(battle)), ([weapon, location]) => (<TriggerAction>weapon).getEffects(ship, location).length > 0);
let result = imap(candidates, ([weapon, location]) => new Maneuver(ship, weapon, location));
return result;
}
@ -149,7 +149,7 @@ module TK.SpaceTac {
let lost = ship.getValue("power") - maneuver.getPowerUsage() + ship.getAttribute("power_generation") - ship.getAttribute("power_capacity");
if (lost > 0) {
return -lost / ship.getAttribute("power_capacity");
} else if (maneuver.action instanceof FireWeaponAction || maneuver.action instanceof DeployDroneAction) {
} else if (maneuver.action instanceof TriggerAction || maneuver.action instanceof DeployDroneAction) {
if (maneuver.effects.length == 0) {
return -1;
} else {

View file

@ -49,9 +49,7 @@ module TK.SpaceTac.Equipments {
new AttributeEffect("power_capacity", 5),
new AttributeEffect("power_generation", 4),
]);
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 1, 0, 0, [
new CooldownEffect(1, 1)
]));
expect(equipment.action).toEqual(new TriggerAction(equipment, [new CooldownEffect(1, 1)]));
expect(equipment.price).toEqual(420);
equipment = template.generate(2);
@ -60,9 +58,7 @@ module TK.SpaceTac.Equipments {
new AttributeEffect("power_capacity", 6),
new AttributeEffect("power_generation", 4),
]);
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 1, 0, 0, [
new CooldownEffect(1, 1)
]));
expect(equipment.action).toEqual(new TriggerAction(equipment, [new CooldownEffect(1, 1)]));
expect(equipment.price).toEqual(1470);
equipment = template.generate(3);
@ -71,9 +67,7 @@ module TK.SpaceTac.Equipments {
new AttributeEffect("power_capacity", 6),
new AttributeEffect("power_generation", 5),
]);
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 1, 0, 0, [
new CooldownEffect(1, 1)
]));
expect(equipment.action).toEqual(new TriggerAction(equipment, [new CooldownEffect(1, 1)]));
expect(equipment.price).toEqual(3570);
equipment = template.generate(10);
@ -82,9 +76,7 @@ module TK.SpaceTac.Equipments {
new AttributeEffect("power_capacity", 13),
new AttributeEffect("power_generation", 12),
]);
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 7, 0, 0, [
new CooldownEffect(4, 7)
]));
expect(equipment.action).toEqual(new TriggerAction(equipment, [new CooldownEffect(4, 7)], 7));
expect(equipment.price).toEqual(47670);
})
})

View file

@ -19,7 +19,7 @@ module TK.SpaceTac.Equipments {
this.setSkillsRequirements({ "skill_time": leveled(1, 1.7), "skill_gravity": leveled(0.3, 0.4) });
this.addAttributeEffect("power_capacity", leveled(5.5, 0.5));
this.addAttributeEffect("power_generation", leveled(4, 0.5));
this.addFireAction(leveled(1, 0.4), irepeat(0), irepeat(0), [
this.addTriggerAction(leveled(1, 0.4), [
new EffectTemplate(new CooldownEffect(), { cooling: leveled(1, 0.2), maxcount: leveled(1, 0.4) })
])
}

View file

@ -69,9 +69,7 @@ module TK.SpaceTac.Equipments {
new AttributeEffect("hull_capacity", 60),
new AttributeEffect("precision", 2),
]);
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 1, 0, 0, [
new ValueEffect("hull", 60)
]))
expect(equipment.action).toEqual(new TriggerAction(equipment, [new ValueEffect("hull", 60)]));
expect(equipment.cooldown).toEqual(new Cooldown(1, 4));
expect(equipment.price).toEqual(250);

View file

@ -27,7 +27,7 @@ module TK.SpaceTac.Equipments {
this.setSkillsRequirements({ "skill_quantum": leveled(1, 2) });
this.addAttributeEffect("hull_capacity", leveled(60));
this.addAttributeEffect("precision", leveled(2));
this.addFireAction(leveled(1, 0.1), irepeat(0), irepeat(0), [
this.addTriggerAction(leveled(1, 0.1), [
new EffectTemplate(new ValueEffect("hull"), { value: leveled(60) })
])
this.setCooldown(irepeat(1), irepeat(4));

View file

@ -5,75 +5,31 @@ module TK.SpaceTac.Equipments {
let equipment = template.generate(1);
expect(equipment.requirements).toEqual({ "skill_antimatter": 1 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 460, 0, [
expect(equipment.action).toEqual(new TriggerAction(equipment, [
new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 2, true)
]));
], 4, 460, 0));
expect(equipment.price).toEqual(100);
equipment = template.generate(2);
expect(equipment.requirements).toEqual({ "skill_antimatter": 2 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 490, 0, [
expect(equipment.action).toEqual(new TriggerAction(equipment, [
new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 2, true)
]));
], 4, 490, 0));
expect(equipment.price).toEqual(350);
equipment = template.generate(3);
expect(equipment.requirements).toEqual({ "skill_antimatter": 4 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 526, 0, [
expect(equipment.action).toEqual(new TriggerAction(equipment, [
new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 2, true)
]));
], 4, 526, 0));
expect(equipment.price).toEqual(850);
equipment = template.generate(10);
expect(equipment.requirements).toEqual({ "skill_antimatter": 25 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 946, 0, [
expect(equipment.action).toEqual(new TriggerAction(equipment, [
new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 2, true)
]));
], 4, 946, 0));
expect(equipment.price).toEqual(11350);
});
it("limits target's AP", () => {
var template = new PowerDepleter();
var equipment = template.generate(1);
var ship = new Ship();
var target = new Ship();
TestTools.setShipAP(ship, 50);
TestTools.setShipAP(target, 7, 2);
expect(target.values.power.get()).toBe(7);
expect(target.sticky_effects).toEqual([]);
// Attribute is immediately limited
nn(equipment.action).apply(ship, Target.newFromShip(target));
expect(target.values.power.get()).toBe(3);
expect(target.sticky_effects).toEqual([
new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 2, true, false)
]);
// Attribute is limited for two turns, and prevents AP recovery
target.values.power.set(6);
target.recoverActionPoints();
target.startTurn();
expect(target.values.power.get()).toBe(3);
expect(target.sticky_effects).toEqual([
new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 1, true, false)
]);
target.endTurn();
target.recoverActionPoints();
expect(target.values.power.get()).toBe(3);
target.startTurn();
expect(target.sticky_effects).toEqual([]);
// Effect vanished, so AP recovery happens
target.endTurn();
expect(target.values.power.get()).toBe(5);
expect(target.sticky_effects).toEqual([]);
});
});
}

View file

@ -7,9 +7,9 @@ module TK.SpaceTac.Equipments {
this.setSkillsRequirements({ "skill_antimatter": leveled(1, 1.5) });
this.setCooldown(irepeat(2), irepeat(3));
this.addFireAction(irepeat(4), leveled(460, 30), irepeat(0), [
this.addTriggerAction(irepeat(4), [
new StickyEffectTemplate(new AttributeLimitEffect("power_capacity"), { "value": irepeat(3) }, irepeat(2))
]);
], leveled(460, 30));
}
}
}

View file

@ -5,25 +5,25 @@ module TK.SpaceTac.Equipments {
let equipment = template.generate(1);
expect(equipment.requirements).toEqual({ "skill_materials": 1 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 3, 500, 0, [new DamageEffect(30, 20)]));
expect(equipment.action).toEqual(new TriggerAction(equipment, [new DamageEffect(30, 20)], 3, 400, 0));
expect(equipment.price).toEqual(100);
expect(equipment.cooldown).toEqual(new Cooldown(2, 2));
equipment = template.generate(2);
expect(equipment.requirements).toEqual({ "skill_materials": 2 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 3, 512, 0, [new DamageEffect(42, 28)]));
expect(equipment.action).toEqual(new TriggerAction(equipment, [new DamageEffect(42, 28)], 3, 412, 0));
expect(equipment.price).toEqual(350);
expect(equipment.cooldown).toEqual(new Cooldown(2, 2));
equipment = template.generate(3);
expect(equipment.requirements).toEqual({ "skill_materials": 4 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 3, 526, 0, [new DamageEffect(56, 37)]));
expect(equipment.action).toEqual(new TriggerAction(equipment, [new DamageEffect(56, 37)], 3, 426, 0));
expect(equipment.price).toEqual(850);
expect(equipment.cooldown).toEqual(new Cooldown(2, 2));
equipment = template.generate(10);
expect(equipment.requirements).toEqual({ "skill_materials": 23 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 3, 694, 0, [new DamageEffect(224, 149)]));
expect(equipment.action).toEqual(new TriggerAction(equipment, [new DamageEffect(224, 149)], 3, 594, 0));
expect(equipment.price).toEqual(11350);
expect(equipment.cooldown).toEqual(new Cooldown(2, 2));
});
@ -33,25 +33,25 @@ module TK.SpaceTac.Equipments {
let equipment = template.generate(1);
expect(equipment.requirements).toEqual({ "skill_materials": 1, "skill_photons": 1 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 500, 150, [new DamageEffect(26, 4)]));
expect(equipment.action).toEqual(new TriggerAction(equipment, [new DamageEffect(26, 4)], 4, 500, 150));
expect(equipment.cooldown).toEqual(new Cooldown(1, 0));
expect(equipment.price).toEqual(163);
equipment = template.generate(2);
expect(equipment.requirements).toEqual({ "skill_materials": 2, "skill_photons": 1 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 520, 155, [new DamageEffect(28, 5)]));
expect(equipment.action).toEqual(new TriggerAction(equipment, [new DamageEffect(28, 5)], 4, 520, 155));
expect(equipment.cooldown).toEqual(new Cooldown(1, 0));
expect(equipment.price).toEqual(570);
equipment = template.generate(3);
expect(equipment.requirements).toEqual({ "skill_materials": 3, "skill_photons": 2 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 544, 161, [new DamageEffect(30, 6)]));
expect(equipment.action).toEqual(new TriggerAction(equipment, [new DamageEffect(30, 6)], 4, 544, 161));
expect(equipment.cooldown).toEqual(new Cooldown(1, 0));
expect(equipment.price).toEqual(1385);
equipment = template.generate(10);
expect(equipment.requirements).toEqual({ "skill_materials": 20, "skill_photons": 13 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 4, 824, 231, [new DamageEffect(58, 20)]));
expect(equipment.action).toEqual(new TriggerAction(equipment, [new DamageEffect(58, 20)], 4, 824, 231));
expect(equipment.cooldown).toEqual(new Cooldown(1, 0));
expect(equipment.price).toEqual(18500);
});
@ -60,26 +60,26 @@ module TK.SpaceTac.Equipments {
let template = new ProkhorovLaser();
let equipment = template.generate(1);
expect(equipment.requirements).toEqual({ "skill_photons": 1 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 5, 0, 250, [new DamageEffect(20, 25)]));
expect(equipment.requirements).toEqual({ "skill_photons": 1, "skill_quantum": 1 });
expect(equipment.action).toEqual(new TriggerAction(equipment, [new DamageEffect(20, 25)], 5, 300, 0, 40));
expect(equipment.cooldown).toEqual(new Cooldown(1, 1));
expect(equipment.price).toEqual(152);
equipment = template.generate(2);
expect(equipment.requirements).toEqual({ "skill_antimatter": 1, "skill_photons": 2 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 5, 0, 260, [new DamageEffect(28, 35)]));
expect(equipment.requirements).toEqual({ "skill_antimatter": 1, "skill_photons": 2, "skill_quantum": 2 });
expect(equipment.action).toEqual(new TriggerAction(equipment, [new DamageEffect(28, 35)], 5, 310, 0, 42));
expect(equipment.cooldown).toEqual(new Cooldown(1, 1));
expect(equipment.price).toEqual(532);
equipment = template.generate(3);
expect(equipment.requirements).toEqual({ "skill_antimatter": 1, "skill_photons": 3 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 5, 0, 272, [new DamageEffect(37, 47)]));
expect(equipment.requirements).toEqual({ "skill_antimatter": 1, "skill_photons": 4, "skill_quantum": 3 });
expect(equipment.action).toEqual(new TriggerAction(equipment, [new DamageEffect(37, 47)], 5, 322, 0, 44));
expect(equipment.cooldown).toEqual(new Cooldown(1, 1));
expect(equipment.price).toEqual(1292);
equipment = template.generate(10);
expect(equipment.requirements).toEqual({ "skill_antimatter": 11, "skill_photons": 22 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 5, 0, 412, [new DamageEffect(149, 187)]));
expect(equipment.requirements).toEqual({ "skill_antimatter": 11, "skill_photons": 23, "skill_quantum": 20 });
expect(equipment.action).toEqual(new TriggerAction(equipment, [new DamageEffect(149, 187)], 5, 462, 0, 72));
expect(equipment.cooldown).toEqual(new Cooldown(1, 1));
expect(equipment.price).toEqual(17252);
});

View file

@ -7,9 +7,9 @@ module TK.SpaceTac.Equipments {
this.setSkillsRequirements({ "skill_materials": leveled(1, 1.4) });
this.setCooldown(irepeat(2), irepeat(2));
this.addFireAction(irepeat(3), leveled(500, 12), irepeat(0), [
this.addTriggerAction(irepeat(3), [
new EffectTemplate(new DamageEffect(), { base: leveled(30), span: leveled(20) })
]);
], leveled(400, 12));
}
}
@ -19,9 +19,9 @@ module TK.SpaceTac.Equipments {
this.setSkillsRequirements({ "skill_materials": leveled(1, 1.2), "skill_photons": leveled(1, 0.8) });
this.setCooldown(irepeat(1), irepeat(0));
this.addFireAction(irepeat(4), leveled(500, 20), leveled(150, 5), [
this.addTriggerAction(irepeat(4), [
new EffectTemplate(new DamageEffect(), { base: leveled(26, 2), span: leveled(4, 1) })
]);
], leveled(500, 20), leveled(150, 5));
}
}
@ -30,12 +30,11 @@ module TK.SpaceTac.Equipments {
super(SlotType.Weapon, "Prokhorov Laser", "Powerful mid-range perforating laser, using antimatter to contain the tremendous photonic energy", 152);
// TODO increased damage to hull
// TODO cone targetting
this.setSkillsRequirements({ "skill_antimatter": leveled(0.3, 0.7), "skill_photons": leveled(1, 1.3) });
this.setSkillsRequirements({ "skill_antimatter": leveled(0.3, 0.7), "skill_quantum": leveled(1, 1.2), "skill_photons": leveled(1, 1.4) });
this.setCooldown(irepeat(1), irepeat(1));
this.addFireAction(irepeat(5), irepeat(0), leveled(250, 10), [
this.addTriggerAction(irepeat(5), [
new EffectTemplate(new DamageEffect(), { base: leveled(20), span: leveled(25) })
]);
], leveled(300, 10), irepeat(0), leveled(40, 2));
}
}
}

View file

@ -6,30 +6,30 @@ module TK.SpaceTac.Equipments {
let equipment = template.generate(1);
expect(equipment.requirements).toEqual({ "skill_gravity": 2 });
expect(equipment.cooldown).toEqual(new Cooldown(3, 3));
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 3, 0, 250, [
expect(equipment.action).toEqual(new TriggerAction(equipment, [
new ValueTransferEffect("shield", -40)
]));
], 3, 0, 250));
equipment = template.generate(2);
expect(equipment.requirements).toEqual({ "skill_gravity": 3 });
expect(equipment.cooldown).toEqual(new Cooldown(3, 3));
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 3, 0, 270, [
expect(equipment.action).toEqual(new TriggerAction(equipment, [
new ValueTransferEffect("shield", -44)
]));
], 3, 0, 270));
equipment = template.generate(3);
expect(equipment.requirements).toEqual({ "skill_gravity": 5 });
expect(equipment.cooldown).toEqual(new Cooldown(3, 3));
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 3, 0, 294, [
expect(equipment.action).toEqual(new TriggerAction(equipment, [
new ValueTransferEffect("shield", -49)
]));
], 3, 0, 294));
equipment = template.generate(10);
expect(equipment.requirements).toEqual({ "skill_gravity": 26 });
expect(equipment.cooldown).toEqual(new Cooldown(3, 3));
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 3, 0, 574, [
expect(equipment.action).toEqual(new TriggerAction(equipment, [
new ValueTransferEffect("shield", -105)
]));
], 3, 0, 574));
})
})
}

View file

@ -7,9 +7,9 @@ module TK.SpaceTac.Equipments {
this.setSkillsRequirements({ "skill_gravity": leveled(2, 1.5) });
this.setCooldown(irepeat(3), irepeat(3));
this.addFireAction(irepeat(3), irepeat(0), leveled(250, 20), [
this.addTriggerAction(irepeat(3), [
new EffectTemplate(new ValueTransferEffect("shield"), { "amount": leveled(-40, -4) })
]);
], irepeat(0), leveled(250, 20));
}
}
}

View file

@ -32,7 +32,7 @@ module TK.SpaceTac.Equipments {
expect(equipment.effects).toEqual([
new AttributeEffect("shield_capacity", 60),
]);
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 2, 0, 300, [new RepelEffect(100)]));
expect(equipment.action).toEqual(new TriggerAction(equipment, [new RepelEffect(100)], 2, 0, 300));
expect(equipment.price).toEqual(140);
equipment = template.generate(2);
@ -40,7 +40,7 @@ module TK.SpaceTac.Equipments {
expect(equipment.effects).toEqual([
new AttributeEffect("shield_capacity", 84),
]);
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 2, 0, 310, [new RepelEffect(105)]));
expect(equipment.action).toEqual(new TriggerAction(equipment, [new RepelEffect(105)], 2, 0, 310));
expect(equipment.price).toEqual(490);
equipment = template.generate(3);
@ -48,7 +48,7 @@ module TK.SpaceTac.Equipments {
expect(equipment.effects).toEqual([
new AttributeEffect("shield_capacity", 112),
]);
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 2, 0, 322, [new RepelEffect(111)]));
expect(equipment.action).toEqual(new TriggerAction(equipment, [new RepelEffect(111)], 2, 0, 322));
expect(equipment.price).toEqual(1190);
equipment = template.generate(10);
@ -56,7 +56,7 @@ module TK.SpaceTac.Equipments {
expect(equipment.effects).toEqual([
new AttributeEffect("shield_capacity", 448),
]);
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 2, 0, 462, [new RepelEffect(181)]));
expect(equipment.action).toEqual(new TriggerAction(equipment, [new RepelEffect(181)], 2, 0, 462));
expect(equipment.price).toEqual(15890);
});

View file

@ -16,9 +16,9 @@ module TK.SpaceTac.Equipments {
this.setSkillsRequirements({ "skill_gravity": leveled(2, 3) });
this.addAttributeEffect("shield_capacity", leveled(60));
this.addFireAction(irepeat(2), irepeat(0), leveled(300, 10), [
this.addTriggerAction(irepeat(2), [
new EffectTemplate(new RepelEffect(), { value: leveled(100, 5) })
]);
], irepeat(0), leveled(300, 10));
}
}

View file

@ -12,7 +12,7 @@ module TK.SpaceTac.UI.Specs {
let action1 = new MoveAction(new Equipment());
nn(action1.equipment).name = "Engine";
action1.name = "Move";
let action2 = new FireWeaponAction(new Equipment(), 2, 50, 0, [new DamageEffect(12)]);
let action2 = new TriggerAction(new Equipment(), [new DamageEffect(12)], 2, 50, 0);
nn(action2.equipment).name = "Weapon";
action2.name = "Fire";
let action3 = new EndTurnAction();

View file

@ -51,7 +51,7 @@ module TK.SpaceTac.UI {
let description = action.getEffectsDescription();
if (description) {
filler.addText(0, 150, description, "#ffffff", 14);
filler.addText(30, 170, description, "#ffffff", 16);
}
let shortcut = "";

View file

@ -44,37 +44,32 @@ module TK.SpaceTac.UI.Specs {
it("updates impact indicators on ships inside the blast radius", function () {
let targetting = newTargetting();
let ship = nn(testgame.battleview.battle.playing_ship);
let impacts = targetting.impact_indicators;
let action = new TriggerAction(new Equipment(), [], 1, 0, 50);
let collect = spyOn(testgame.battleview.battle, "collectShipsInCircle").and.returnValues(
let collect = spyOn(action, "getImpactedShips").and.returnValues(
[new Ship(), new Ship(), new Ship()],
[new Ship(), new Ship()],
[]);
targetting.updateImpactIndicators(ship, new Target(20, 10), 50);
targetting.updateImpactIndicators(impacts, ship, action, new Target(20, 10));
expect(collect).toHaveBeenCalledTimes(1);
expect(collect).toHaveBeenCalledWith(new Target(20, 10), 50, true);
expect(targetting.fire_impact.children.length).toBe(3);
expect(targetting.fire_impact.visible).toBe(true);
expect(collect).toHaveBeenCalledWith(ship, new Target(20, 10), ship.location);
expect(targetting.impact_indicators.children.length).toBe(3);
expect(targetting.impact_indicators.visible).toBe(true);
targetting.updateImpactIndicators(ship, new Target(20, 11), 50);
targetting.updateImpactIndicators(impacts, ship, action, new Target(20, 11));
expect(collect).toHaveBeenCalledTimes(2);
expect(collect).toHaveBeenCalledWith(new Target(20, 11), 50, true);
expect(targetting.fire_impact.children.length).toBe(2);
expect(targetting.fire_impact.visible).toBe(true);
expect(collect).toHaveBeenCalledWith(ship, new Target(20, 11), ship.location);
expect(targetting.impact_indicators.children.length).toBe(2);
expect(targetting.impact_indicators.visible).toBe(true);
let target = Target.newFromShip(new Ship());
targetting.updateImpactIndicators(ship, target, 0);
expect(collect).toHaveBeenCalledTimes(2);
expect(targetting.fire_impact.children.length).toBe(1);
expect(targetting.fire_impact.visible).toBe(true);
targetting.updateImpactIndicators(ship, new Target(20, 12), 50);
targetting.updateImpactIndicators(impacts, ship, action, new Target(20, 12));
expect(collect).toHaveBeenCalledTimes(3);
expect(collect).toHaveBeenCalledWith(new Target(20, 12), 50, true);
expect(targetting.fire_impact.visible).toBe(false);
expect(collect).toHaveBeenCalledWith(ship, new Target(20, 12), ship.location);
expect(targetting.impact_indicators.visible).toBe(false);
})
it("updates graphics from simulation", function () {
@ -109,8 +104,8 @@ module TK.SpaceTac.UI.Specs {
expect(targetting.fire_arrow.visible).toBe(true);
expect(targetting.fire_arrow.position).toEqual(jasmine.objectContaining({ x: 156, y: 65 }));
expect(targetting.fire_arrow.rotation).toBeCloseTo(0.534594, 5);
expect(targetting.fire_blast.visible).toBe(true);
expect(targetting.fire_blast.position).toEqual(jasmine.objectContaining({ x: 156, y: 65 }));
expect(targetting.impact_area.visible).toBe(true);
expect(targetting.impact_area.position).toEqual(jasmine.objectContaining({ x: 156, y: 65 }));
expect(targetting.move_ghost.visible).toBe(true);
expect(targetting.move_ghost.position).toEqual(jasmine.objectContaining({ x: 80, y: 20 }));
expect(targetting.move_ghost.rotation).toBeCloseTo(0.534594, 5);

View file

@ -15,14 +15,14 @@ module TK.SpaceTac.UI {
mode: ActionTargettingMode
simulation = new MoveFireResult()
// Movement projector
// Move and fire lines
drawn_info: Phaser.Graphics
move_ghost: Phaser.Image
// Fire projector
fire_arrow: Phaser.Image
fire_blast: Phaser.Image
fire_impact: Phaser.Group
// Impact area
impact_area: Phaser.Graphics
impact_indicators: Phaser.Group
// Collaborators to update
actionbar: ActionBar
@ -50,17 +50,16 @@ module TK.SpaceTac.UI {
this.fire_arrow = this.view.newImage("battle-hud-simulator-ok");
this.fire_arrow.anchor.set(1, 0.5);
this.fire_arrow.visible = false;
this.fire_impact = new Phaser.Group(view.game);
this.fire_impact.visible = false;
this.fire_blast = new Phaser.Image(view.game, 0, 0, "battle-arena-blast");
this.fire_blast.anchor.set(0.5, 0.5);
this.fire_blast.visible = false;
this.impact_indicators = new Phaser.Group(view.game);
this.impact_indicators.visible = false;
this.impact_area = new Phaser.Graphics(view.game);
this.impact_area.visible = false;
this.container.add(this.fire_impact);
this.container.add(this.fire_blast);
this.container.add(this.impact_indicators);
this.container.add(this.impact_area);
this.container.add(this.drawn_info);
this.container.add(this.fire_arrow);
this.container.add(this.move_ghost);
this.container.add(this.fire_arrow);
}
/**
@ -118,31 +117,58 @@ module TK.SpaceTac.UI {
}
/**
* Update impact indicators
* Update impact indicators (highlighting impacted ships)
*/
updateImpactIndicators(ship: Ship, target: Target, radius: number): void {
let ships: Ship[];
if (radius) {
let battle = ship.getBattle();
if (battle) {
ships = battle.collectShipsInCircle(target, radius, true);
} else {
ships = [];
}
} else {
ships = target.ship ? [target.ship] : [];
}
updateImpactIndicators(impacts: Phaser.Group, ship: Ship, action: BaseAction, target: Target, source: IArenaLocation = ship.location): void {
let ships = action.getImpactedShips(ship, target, source);
if (ships.length) {
this.fire_impact.removeAll(true);
// TODO differential
impacts.removeAll(true);
ships.forEach(iship => {
let indicator = this.view.newImage("battle-hud-ship-impacted", iship.arena_x, iship.arena_y);
indicator.anchor.set(0.5);
this.fire_impact.add(indicator);
impacts.add(indicator);
});
this.fire_impact.visible = true;
impacts.visible = true;
} else {
this.fire_impact.visible = false;
impacts.visible = false;
}
}
/**
* Update impact graphics (area display)
*/
updateImpactArea(area: Phaser.Graphics, action: BaseAction): void {
area.clear();
let color = 0;
let radius = 0;
let angle = 0;
if (action instanceof TriggerAction) {
color = 0x90481e;
if (action.angle) {
angle = (action.angle * 0.5) * Math.PI / 180;
radius = action.range;
} else {
radius = action.blast;
}
} else if (action instanceof DeployDroneAction) {
color = 0xe9f2f9;
radius = action.effect_radius;
} else if (action instanceof ToggleAction) {
color = 0xd3e448;
radius = action.radius;
}
if (radius) {
area.lineStyle(2, 0x90481e, 0.6);
area.beginFill(0x90481e, 0.2);
if (angle) {
area.arc(0, 0, radius, angle, -angle, true);
} else {
area.drawCircle(0, 0, radius * 2);
}
area.endFill();
}
}
@ -177,24 +203,24 @@ module TK.SpaceTac.UI {
}
if (simulation.need_fire) {
let blast = this.action.getBlastRadius(this.ship);
if (blast) {
this.fire_blast.position.set(this.target.x, this.target.y);
this.fire_blast.scale.set(blast * 2 / 365);
this.fire_blast.alpha = simulation.can_fire ? 1 : 0.5;
this.fire_blast.visible = true;
if (this.action instanceof TriggerAction && this.action.angle) {
this.impact_area.position.set(simulation.move_location.x, simulation.move_location.y);
this.impact_area.rotation = arenaAngle(simulation.move_location, simulation.fire_location);
} else {
this.fire_blast.visible = false;
this.impact_area.position.set(this.target.x, this.target.y);
}
this.updateImpactIndicators(this.ship, this.target, blast);
this.impact_area.alpha = simulation.can_fire ? 1 : 0.5;
this.impact_area.visible = true;
this.updateImpactIndicators(this.impact_indicators, this.ship, this.action, this.target, this.simulation.move_location);
this.fire_arrow.position.set(this.target.x, this.target.y);
this.fire_arrow.rotation = angle;
this.view.changeImage(this.fire_arrow, simulation.complete ? "battle-hud-simulator-ok" : "battle-hud-simulator-power");
this.fire_arrow.visible = true;
} else {
this.fire_blast.visible = false;
this.fire_impact.visible = false;
this.impact_area.visible = false;
this.impact_indicators.visible = false;
this.fire_arrow.visible = false;
}
} else {
@ -203,7 +229,7 @@ module TK.SpaceTac.UI {
this.fire_arrow.rotation = angle;
this.view.changeImage(this.fire_arrow, "battle-hud-simulator-failed");
this.fire_arrow.visible = true;
this.fire_blast.visible = false;
this.impact_area.visible = false;
}
this.container.visible = true;
} else {
@ -270,6 +296,8 @@ module TK.SpaceTac.UI {
this.view.changeImage(this.move_ghost, `ship-${this.ship.model.code}-sprite`);
this.move_ghost.scale.set(0.4);
this.updateImpactArea(this.impact_area, this.action);
this.setTarget(action.getDefaultTarget(this.ship));
} else {
this.ship = null;

View file

@ -161,7 +161,7 @@ module TK.SpaceTac.UI {
missile.rotation = arenaAngle(this.source, this.destination);
this.layer.add(missile);
let blast_radius = this.weapon.action ? this.weapon.action.getBlastRadius(this.ship) : 0;
let blast_radius = (this.weapon.action instanceof TriggerAction) ? this.weapon.action.blast : 0;
let projectile_duration = arenaDistance(this.source, this.destination) * 1.5;
let tween = this.ui.tweens.create(missile);
@ -185,7 +185,7 @@ module TK.SpaceTac.UI {
});
tween.start();
if (blast_radius > 0 && this.weapon.action instanceof FireWeaponAction) {
if (blast_radius > 0 && this.weapon.action instanceof TriggerAction) {
if (any(this.weapon.action.effects, effect => effect instanceof DamageEffect)) {
let ships = this.arena.getShipsInCircle(new ArenaCircleArea(this.destination.x, this.destination.y, blast_radius));
ships.forEach(sprite => {

View file

@ -1315,7 +1315,7 @@ istanbul@0.4.5, istanbul@^0.4.0:
which "^1.1.1"
wordwrap "^1.0.0"
jasmine-core@^2.8.0, jasmine-core@~2.8.0:
jasmine-core@2.8.0, jasmine-core@~2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e"