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" "typescript": "^2.5.3"
}, },
"dependencies": { "dependencies": {
"jasmine-core": "^2.8.0", "jasmine-core": "2.8.0",
"parse": "^1.9.2", "parse": "^1.9.2",
"phaser": "^2.6.2", "phaser": "^2.6.2",
"phaser-plugin-scene-graph": "^1.0.4" "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 -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/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 "$@" PATH="${dir}/.env/node/bin:${PATH}" yarn "$@"

View file

@ -1,8 +1,15 @@
module TK.SpaceTac.Specs { module TK.SpaceTac.Specs {
describe("ArenaLocation", () => { 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(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); 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); 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 * 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 dx = loc2.x - loc1.x;
let dy = loc2.y - loc1.y; let dy = loc2.y - loc1.y;
return Math.sqrt(dx * dx + dy * dy); return Math.sqrt(dx * dx + dy * dy);
@ -70,7 +77,7 @@ module TK.SpaceTac {
/** /**
* Check if a location is inside an area * 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); let dist = arenaDistance(loc1, loc2);
return border_inclusive ? (dist <= loc2.radius) : (dist < loc2.radius); return border_inclusive ? (dist <= loc2.radius) : (dist < loc2.radius);
} }

View file

@ -47,9 +47,7 @@ module TK.SpaceTac.Specs {
let equipment = new Equipment(); let equipment = new Equipment();
expect(equipment.getEffectsDescription()).toEqual("does nothing"); expect(equipment.getEffectsDescription()).toEqual("does nothing");
let action = new FireWeaponAction(equipment, 1, 200, 0, [ let action = new TriggerAction(equipment, [new DamageEffect(50)], 1, 200, 0);
new DamageEffect(50)
]);
equipment.action = action; equipment.action = action;
expect(equipment.getEffectsDescription()).toEqual("Fire (power usage 1, max range 200km):\n• do 50 damage on target"); 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); equipment.effects.forEach(effectFactor);
if (equipment.action instanceof FireWeaponAction) { if (equipment.action instanceof TriggerAction) {
simpleFactor(equipment.action, 'power', true); simpleFactor(equipment.action, 'power', true);
simpleFactor(equipment.action, 'blast'); simpleFactor(equipment.action, 'blast');
simpleFactor(equipment.action, 'range'); simpleFactor(equipment.action, 'range');

View file

@ -95,15 +95,15 @@ module TK.SpaceTac.Specs {
it("adds fire actions", function () { it("adds fire actions", function () {
let template = new LootTemplate(SlotType.Weapon, "Weapon"); 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) }) new EffectTemplate(new FakeEffect(3), { "fakevalue": istep(8) })
]); ], istep(100), istep(50), istep(10));
let result = template.generate(1); 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); 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 () { it("adds drone actions", function () {
@ -126,10 +126,10 @@ module TK.SpaceTac.Specs {
template.addAttributeEffect("maneuvrability", irepeat(1)); template.addAttributeEffect("maneuvrability", irepeat(1));
expect(template.hasDamageEffect()).toBe(false); 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); 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); 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) => { this.base_modifiers.push((equipment, level) => {
let reffects = effects.map(effect => effect.generate(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 { hasDamageEffect(): boolean {
let example = this.generate(1); let example = this.generate(1);
let action = example.action; 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)); return any(action.effects, effect => effect instanceof DamageEffect || (effect instanceof StickyEffect && effect.base instanceof DamageEffect));
} else { } else {
return false; return false;

View file

@ -5,7 +5,7 @@ module TK.SpaceTac.Specs {
let ship = new Ship(); let ship = new Ship();
TestTools.setShipAP(ship, ship_ap); TestTools.setShipAP(ship, ship_ap);
TestTools.addEngine(ship, engine_distance); 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); let simulator = new MoveFireSimulator(ship);
return [ship, simulator, action]; return [ship, simulator, action];
} }

View file

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

View file

@ -436,7 +436,7 @@ module TK.SpaceTac {
let start = copy(this.location); let start = copy(this.location);
let area_effects = imaterialize(this.iToggleActions(true)); 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; let old_area_effects = this.getActiveEffects().area;
if (engine) { if (engine) {
@ -450,7 +450,7 @@ module TK.SpaceTac {
this.addBattleEvent(new MoveEvent(this, start, copy(this.location), engine)); 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 diff_impacted_ships = flatten(zip(old_impacted_ships, new_impacted_ships).map(([a, b]) => disjunctunion(a, b)));
let new_area_effects = this.getActiveEffects().area; let new_area_effects = this.getActiveEffects().area;
if (disjunctunion(old_area_effects, new_area_effects).length > 0) { 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 * 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)); 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; return equipment;
} }

View file

@ -82,24 +82,5 @@ module TK.SpaceTac {
expect(power.wear).toBe(1); expect(power.wear).toBe(1);
expect(equipment.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 * Get the targetting mode
*/ */
getTargettingMode(ship: Ship): ActionTargettingMode { getTargettingMode(ship: Ship): ActionTargettingMode {
let blast = this.getBlastRadius(ship); return ActionTargettingMode.SELF;
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;
}
} }
/** /**
@ -119,7 +106,11 @@ module TK.SpaceTac {
return null; 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 { getActionPointsUsage(ship: Ship, target: Target | null): number {
return 0; return 0;
} }
@ -129,9 +120,25 @@ module TK.SpaceTac {
return 0; return 0;
} }
// Get the effect area radius of this action /**
getBlastRadius(ship: Ship): number { * Filter a list of ships to return only those impacted by this action
return 0; *
* 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 { module TK.SpaceTac {
describe("DeployDroneAction", function () { describe("DeployDroneAction", function () {
it("stores useful information", function () { it("stores useful information", function () {

View file

@ -33,6 +33,10 @@ module TK.SpaceTac {
this.effects = effects; this.effects = effects;
} }
getTargettingMode(ship: Ship): ActionTargettingMode {
return ActionTargettingMode.SPACE;
}
getActionPointsUsage(ship: Ship, target: Target | null): number { getActionPointsUsage(ship: Ship, target: Target | null): number {
return this.power; return this.power;
} }
@ -41,8 +45,8 @@ module TK.SpaceTac {
return this.deploy_distance; return this.deploy_distance;
} }
getBlastRadius(ship: Ship): number { filterImpactedShips(source: ArenaLocation, target: Target, ships: Ship[]): Ship[] {
return this.effect_radius; return ships.filter(ship => arenaDistance(ship.location, target) <= this.effect_radius);
} }
checkLocationTarget(ship: Ship, target: Target): Target { 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 { getTargettingMode(ship: Ship): ActionTargettingMode {
if (this.activated) { if (this.activated || !this.radius) {
return ActionTargettingMode.SELF; return ActionTargettingMode.SELF_CONFIRM;
} else { } else {
return super.getTargettingMode(ship); return ActionTargettingMode.SURROUNDINGS;
} }
} }
@ -44,30 +44,20 @@ module TK.SpaceTac {
return 0; return 0;
} }
getBlastRadius(ship: Ship): number { filterImpactedShips(source: ArenaLocation, target: Target, ships: Ship[]): Ship[] {
return this.radius; return ships.filter(ship => arenaDistance(ship.location, source) <= this.radius);
} }
checkShipTarget(ship: Ship, target: Target): Target | null { checkShipTarget(ship: Ship, target: Target): Target | null {
return (ship == target.ship) ? 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 * 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 result: [Ship, BaseEffect][] = [];
let ships = this.getAffectedShips(ship); let ships = this.getImpactedShips(ship, target, source);
ships.forEach(ship => { ships.forEach(ship => {
this.effects.forEach(effect => result.push([ship, effect])); this.effects.forEach(effect => result.push([ship, effect]));
}); });
@ -77,7 +67,7 @@ module TK.SpaceTac {
protected customApply(ship: Ship, target: Target) { protected customApply(ship: Ship, target: Target) {
this.activated = !this.activated; this.activated = !this.activated;
ship.addBattleEvent(new ToggleEvent(ship, this, 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 { getEffectsDescription(): string {

View file

@ -1,15 +1,13 @@
/// <reference path="../effects/BaseEffect.ts" />
module TK.SpaceTac { module TK.SpaceTac {
describe("FireWeaponAction", function () { describe("TriggerAction", function () {
it("constructs correctly", function () { it("constructs correctly", function () {
let equipment = new Equipment(SlotType.Weapon, "testweapon"); 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.code).toEqual("fire-testweapon");
expect(action.name).toEqual("Fire"); expect(action.name).toEqual("Fire");
expect(action.equipment).toBe(equipment); expect(action.equipment).toBe(equipment);
}); })
it("applies effects to alive ships in blast radius", function () { it("applies effects to alive ships in blast radius", function () {
let fleet = new Fleet(); let fleet = new Fleet();
@ -17,7 +15,7 @@ module TK.SpaceTac {
let equipment = new Equipment(SlotType.Weapon, "testweapon"); let equipment = new Equipment(SlotType.Weapon, "testweapon");
let effect = new BaseEffect("testeffect"); let effect = new BaseEffect("testeffect");
let mock_apply = spyOn(effect, "applyOnShip").and.stub(); 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); TestTools.setShipAP(ship, 10);
@ -37,7 +35,7 @@ module TK.SpaceTac {
action.apply(ship, Target.newFromLocation(50, 50)); action.apply(ship, Target.newFromLocation(50, 50));
expect(mock_apply).toHaveBeenCalledTimes(1); expect(mock_apply).toHaveBeenCalledTimes(1);
expect(mock_apply).toHaveBeenCalledWith(ship2, ship); expect(mock_apply).toHaveBeenCalledWith(ship2, ship);
}); })
it("transforms ship target in location target, when the weapon has blast radius", function () { it("transforms ship target in location target, when the weapon has blast radius", function () {
let ship1 = new Ship(); let ship1 = new Ship();
@ -62,7 +60,46 @@ module TK.SpaceTac {
target = action.checkTarget(ship1, Target.newFromShip(ship2)); target = action.checkTarget(ship1, Target.newFromShip(ship2));
expect(target).toEqual(new Target(100, 10)); 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 () { it("rotates toward the target", function () {
let ship = new Ship(); let ship = new Ship();
@ -78,6 +115,6 @@ module TK.SpaceTac {
result = action.apply(ship, Target.newFromShip(ship)); result = action.apply(ship, Target.newFromShip(ship));
expect(result).toBe(true); expect(result).toBe(true);
expect(ship.arena_angle).toBeCloseTo(1.107, 0.001); expect(ship.arena_angle).toBeCloseTo(1.107, 0.001);
}); })
}); });
} }

View file

@ -2,31 +2,35 @@
module TK.SpaceTac { 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 consumption
power: number power: number
// Maximal range of the weapon // Maximal range of the weapon (distance to target)
range: number range: number
// Blast radius // Radius around the target that will be impacted
blast: number blast: number
// Angle of the area between the source and the target that will be impacted
angle: number
// Effects applied on target // Effects applied on target
effects: BaseEffect[] effects: BaseEffect[]
// Equipment cannot be null // Equipment cannot be null
equipment: Equipment 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); super("fire-" + equipment.code, name, equipment);
this.power = power; this.power = power;
this.range = range; this.range = range;
this.effects = effects; this.effects = effects;
this.blast = blast; this.blast = blast;
this.angle = angle;
} }
getDefaultTarget(ship: Ship): Target { 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 { getActionPointsUsage(ship: Ship, target: Target | null): number {
return this.power; return this.power;
} }
@ -54,12 +76,20 @@ module TK.SpaceTac {
return this.range; return this.range;
} }
getBlastRadius(ship: Ship): number { filterImpactedShips(source: ArenaLocation, target: Target, ships: Ship[]): Ship[] {
return this.blast; 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 { 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); target = target.constraintInRange(ship.arena_x, ship.arena_y, this.range);
return target; return target;
} else { } else {
@ -73,7 +103,7 @@ module TK.SpaceTac {
return null; return null;
} else { } else {
// Check if target is in range // 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)); return this.checkLocationTarget(ship, new Target(target.x, target.y));
} else if (target.isInRange(ship.arena_x, ship.arena_y, this.range)) { } else if (target.isInRange(ship.arena_x, ship.arena_y, this.range)) {
return target; return target;
@ -86,11 +116,9 @@ module TK.SpaceTac {
/** /**
* Collect the effects applied by this action * 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 result: [Ship, BaseEffect][] = [];
let blast = this.getBlastRadius(ship); let ships = this.getImpactedShips(ship, target, source);
let battle = ship.getBattle();
let ships = (blast && battle) ? battle.collectShipsInCircle(target, blast, true) : ((target.ship && target.ship.alive) ? [target.ship] : []);
ships.forEach(ship => { ships.forEach(ship => {
this.effects.forEach(effect => result.push([ship, effect])); this.effects.forEach(effect => result.push([ship, effect]));
}); });
@ -126,7 +154,16 @@ module TK.SpaceTac {
let desc = `${this.name} (${info.join(", ")})`; let desc = `${this.name} (${info.join(", ")})`;
let effects = this.effects.map(effect => { 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 "• " + effect.getDescription() + " " + suffix;
}); });
return `${desc}:\n${effects.join("\n")}`; return `${desc}:\n${effects.join("\n")}`;

View file

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

View file

@ -49,9 +49,7 @@ module TK.SpaceTac.Equipments {
new AttributeEffect("power_capacity", 5), new AttributeEffect("power_capacity", 5),
new AttributeEffect("power_generation", 4), new AttributeEffect("power_generation", 4),
]); ]);
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 1, 0, 0, [ expect(equipment.action).toEqual(new TriggerAction(equipment, [new CooldownEffect(1, 1)]));
new CooldownEffect(1, 1)
]));
expect(equipment.price).toEqual(420); expect(equipment.price).toEqual(420);
equipment = template.generate(2); equipment = template.generate(2);
@ -60,9 +58,7 @@ module TK.SpaceTac.Equipments {
new AttributeEffect("power_capacity", 6), new AttributeEffect("power_capacity", 6),
new AttributeEffect("power_generation", 4), new AttributeEffect("power_generation", 4),
]); ]);
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 1, 0, 0, [ expect(equipment.action).toEqual(new TriggerAction(equipment, [new CooldownEffect(1, 1)]));
new CooldownEffect(1, 1)
]));
expect(equipment.price).toEqual(1470); expect(equipment.price).toEqual(1470);
equipment = template.generate(3); equipment = template.generate(3);
@ -71,9 +67,7 @@ module TK.SpaceTac.Equipments {
new AttributeEffect("power_capacity", 6), new AttributeEffect("power_capacity", 6),
new AttributeEffect("power_generation", 5), new AttributeEffect("power_generation", 5),
]); ]);
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 1, 0, 0, [ expect(equipment.action).toEqual(new TriggerAction(equipment, [new CooldownEffect(1, 1)]));
new CooldownEffect(1, 1)
]));
expect(equipment.price).toEqual(3570); expect(equipment.price).toEqual(3570);
equipment = template.generate(10); equipment = template.generate(10);
@ -82,9 +76,7 @@ module TK.SpaceTac.Equipments {
new AttributeEffect("power_capacity", 13), new AttributeEffect("power_capacity", 13),
new AttributeEffect("power_generation", 12), new AttributeEffect("power_generation", 12),
]); ]);
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 7, 0, 0, [ expect(equipment.action).toEqual(new TriggerAction(equipment, [new CooldownEffect(4, 7)], 7));
new CooldownEffect(4, 7)
]));
expect(equipment.price).toEqual(47670); 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.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_capacity", leveled(5.5, 0.5));
this.addAttributeEffect("power_generation", leveled(4, 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) }) 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("hull_capacity", 60),
new AttributeEffect("precision", 2), new AttributeEffect("precision", 2),
]); ]);
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 1, 0, 0, [ expect(equipment.action).toEqual(new TriggerAction(equipment, [new ValueEffect("hull", 60)]));
new ValueEffect("hull", 60)
]))
expect(equipment.cooldown).toEqual(new Cooldown(1, 4)); expect(equipment.cooldown).toEqual(new Cooldown(1, 4));
expect(equipment.price).toEqual(250); expect(equipment.price).toEqual(250);

View file

@ -27,7 +27,7 @@ module TK.SpaceTac.Equipments {
this.setSkillsRequirements({ "skill_quantum": leveled(1, 2) }); this.setSkillsRequirements({ "skill_quantum": leveled(1, 2) });
this.addAttributeEffect("hull_capacity", leveled(60)); this.addAttributeEffect("hull_capacity", leveled(60));
this.addAttributeEffect("precision", leveled(2)); 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) }) new EffectTemplate(new ValueEffect("hull"), { value: leveled(60) })
]) ])
this.setCooldown(irepeat(1), irepeat(4)); this.setCooldown(irepeat(1), irepeat(4));

View file

@ -5,75 +5,31 @@ module TK.SpaceTac.Equipments {
let equipment = template.generate(1); let equipment = template.generate(1);
expect(equipment.requirements).toEqual({ "skill_antimatter": 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) new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 2, true)
])); ], 4, 460, 0));
expect(equipment.price).toEqual(100); expect(equipment.price).toEqual(100);
equipment = template.generate(2); equipment = template.generate(2);
expect(equipment.requirements).toEqual({ "skill_antimatter": 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) new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 2, true)
])); ], 4, 490, 0));
expect(equipment.price).toEqual(350); expect(equipment.price).toEqual(350);
equipment = template.generate(3); equipment = template.generate(3);
expect(equipment.requirements).toEqual({ "skill_antimatter": 4 }); 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) new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 2, true)
])); ], 4, 526, 0));
expect(equipment.price).toEqual(850); expect(equipment.price).toEqual(850);
equipment = template.generate(10); equipment = template.generate(10);
expect(equipment.requirements).toEqual({ "skill_antimatter": 25 }); 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) new StickyEffect(new AttributeLimitEffect("power_capacity", 3), 2, true)
])); ], 4, 946, 0));
expect(equipment.price).toEqual(11350); 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.setSkillsRequirements({ "skill_antimatter": leveled(1, 1.5) });
this.setCooldown(irepeat(2), irepeat(3)); 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)) 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); let equipment = template.generate(1);
expect(equipment.requirements).toEqual({ "skill_materials": 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.price).toEqual(100);
expect(equipment.cooldown).toEqual(new Cooldown(2, 2)); expect(equipment.cooldown).toEqual(new Cooldown(2, 2));
equipment = template.generate(2); equipment = template.generate(2);
expect(equipment.requirements).toEqual({ "skill_materials": 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.price).toEqual(350);
expect(equipment.cooldown).toEqual(new Cooldown(2, 2)); expect(equipment.cooldown).toEqual(new Cooldown(2, 2));
equipment = template.generate(3); equipment = template.generate(3);
expect(equipment.requirements).toEqual({ "skill_materials": 4 }); 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.price).toEqual(850);
expect(equipment.cooldown).toEqual(new Cooldown(2, 2)); expect(equipment.cooldown).toEqual(new Cooldown(2, 2));
equipment = template.generate(10); equipment = template.generate(10);
expect(equipment.requirements).toEqual({ "skill_materials": 23 }); 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.price).toEqual(11350);
expect(equipment.cooldown).toEqual(new Cooldown(2, 2)); expect(equipment.cooldown).toEqual(new Cooldown(2, 2));
}); });
@ -33,25 +33,25 @@ module TK.SpaceTac.Equipments {
let equipment = template.generate(1); let equipment = template.generate(1);
expect(equipment.requirements).toEqual({ "skill_materials": 1, "skill_photons": 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.cooldown).toEqual(new Cooldown(1, 0));
expect(equipment.price).toEqual(163); expect(equipment.price).toEqual(163);
equipment = template.generate(2); equipment = template.generate(2);
expect(equipment.requirements).toEqual({ "skill_materials": 2, "skill_photons": 1 }); 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.cooldown).toEqual(new Cooldown(1, 0));
expect(equipment.price).toEqual(570); expect(equipment.price).toEqual(570);
equipment = template.generate(3); equipment = template.generate(3);
expect(equipment.requirements).toEqual({ "skill_materials": 3, "skill_photons": 2 }); 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.cooldown).toEqual(new Cooldown(1, 0));
expect(equipment.price).toEqual(1385); expect(equipment.price).toEqual(1385);
equipment = template.generate(10); equipment = template.generate(10);
expect(equipment.requirements).toEqual({ "skill_materials": 20, "skill_photons": 13 }); 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.cooldown).toEqual(new Cooldown(1, 0));
expect(equipment.price).toEqual(18500); expect(equipment.price).toEqual(18500);
}); });
@ -60,26 +60,26 @@ module TK.SpaceTac.Equipments {
let template = new ProkhorovLaser(); let template = new ProkhorovLaser();
let equipment = template.generate(1); let equipment = template.generate(1);
expect(equipment.requirements).toEqual({ "skill_photons": 1 }); expect(equipment.requirements).toEqual({ "skill_photons": 1, "skill_quantum": 1 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 5, 0, 250, [new DamageEffect(20, 25)])); 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.cooldown).toEqual(new Cooldown(1, 1));
expect(equipment.price).toEqual(152); expect(equipment.price).toEqual(152);
equipment = template.generate(2); equipment = template.generate(2);
expect(equipment.requirements).toEqual({ "skill_antimatter": 1, "skill_photons": 2 }); expect(equipment.requirements).toEqual({ "skill_antimatter": 1, "skill_photons": 2, "skill_quantum": 2 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 5, 0, 260, [new DamageEffect(28, 35)])); 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.cooldown).toEqual(new Cooldown(1, 1));
expect(equipment.price).toEqual(532); expect(equipment.price).toEqual(532);
equipment = template.generate(3); equipment = template.generate(3);
expect(equipment.requirements).toEqual({ "skill_antimatter": 1, "skill_photons": 3 }); expect(equipment.requirements).toEqual({ "skill_antimatter": 1, "skill_photons": 4, "skill_quantum": 3 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 5, 0, 272, [new DamageEffect(37, 47)])); 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.cooldown).toEqual(new Cooldown(1, 1));
expect(equipment.price).toEqual(1292); expect(equipment.price).toEqual(1292);
equipment = template.generate(10); equipment = template.generate(10);
expect(equipment.requirements).toEqual({ "skill_antimatter": 11, "skill_photons": 22 }); expect(equipment.requirements).toEqual({ "skill_antimatter": 11, "skill_photons": 23, "skill_quantum": 20 });
expect(equipment.action).toEqual(new FireWeaponAction(equipment, 5, 0, 412, [new DamageEffect(149, 187)])); 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.cooldown).toEqual(new Cooldown(1, 1));
expect(equipment.price).toEqual(17252); expect(equipment.price).toEqual(17252);
}); });

View file

@ -7,9 +7,9 @@ module TK.SpaceTac.Equipments {
this.setSkillsRequirements({ "skill_materials": leveled(1, 1.4) }); this.setSkillsRequirements({ "skill_materials": leveled(1, 1.4) });
this.setCooldown(irepeat(2), irepeat(2)); 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) }) 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.setSkillsRequirements({ "skill_materials": leveled(1, 1.2), "skill_photons": leveled(1, 0.8) });
this.setCooldown(irepeat(1), irepeat(0)); 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) }) 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); 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 increased damage to hull
// TODO cone targetting this.setSkillsRequirements({ "skill_antimatter": leveled(0.3, 0.7), "skill_quantum": leveled(1, 1.2), "skill_photons": leveled(1, 1.4) });
this.setSkillsRequirements({ "skill_antimatter": leveled(0.3, 0.7), "skill_photons": leveled(1, 1.3) });
this.setCooldown(irepeat(1), irepeat(1)); 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) }) 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); let equipment = template.generate(1);
expect(equipment.requirements).toEqual({ "skill_gravity": 2 }); expect(equipment.requirements).toEqual({ "skill_gravity": 2 });
expect(equipment.cooldown).toEqual(new Cooldown(3, 3)); 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) new ValueTransferEffect("shield", -40)
])); ], 3, 0, 250));
equipment = template.generate(2); equipment = template.generate(2);
expect(equipment.requirements).toEqual({ "skill_gravity": 3 }); expect(equipment.requirements).toEqual({ "skill_gravity": 3 });
expect(equipment.cooldown).toEqual(new Cooldown(3, 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) new ValueTransferEffect("shield", -44)
])); ], 3, 0, 270));
equipment = template.generate(3); equipment = template.generate(3);
expect(equipment.requirements).toEqual({ "skill_gravity": 5 }); expect(equipment.requirements).toEqual({ "skill_gravity": 5 });
expect(equipment.cooldown).toEqual(new Cooldown(3, 3)); 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) new ValueTransferEffect("shield", -49)
])); ], 3, 0, 294));
equipment = template.generate(10); equipment = template.generate(10);
expect(equipment.requirements).toEqual({ "skill_gravity": 26 }); expect(equipment.requirements).toEqual({ "skill_gravity": 26 });
expect(equipment.cooldown).toEqual(new Cooldown(3, 3)); 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) 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.setSkillsRequirements({ "skill_gravity": leveled(2, 1.5) });
this.setCooldown(irepeat(3), irepeat(3)); 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) }) 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([ expect(equipment.effects).toEqual([
new AttributeEffect("shield_capacity", 60), 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); expect(equipment.price).toEqual(140);
equipment = template.generate(2); equipment = template.generate(2);
@ -40,7 +40,7 @@ module TK.SpaceTac.Equipments {
expect(equipment.effects).toEqual([ expect(equipment.effects).toEqual([
new AttributeEffect("shield_capacity", 84), 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); expect(equipment.price).toEqual(490);
equipment = template.generate(3); equipment = template.generate(3);
@ -48,7 +48,7 @@ module TK.SpaceTac.Equipments {
expect(equipment.effects).toEqual([ expect(equipment.effects).toEqual([
new AttributeEffect("shield_capacity", 112), 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); expect(equipment.price).toEqual(1190);
equipment = template.generate(10); equipment = template.generate(10);
@ -56,7 +56,7 @@ module TK.SpaceTac.Equipments {
expect(equipment.effects).toEqual([ expect(equipment.effects).toEqual([
new AttributeEffect("shield_capacity", 448), 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); expect(equipment.price).toEqual(15890);
}); });

View file

@ -16,9 +16,9 @@ module TK.SpaceTac.Equipments {
this.setSkillsRequirements({ "skill_gravity": leveled(2, 3) }); this.setSkillsRequirements({ "skill_gravity": leveled(2, 3) });
this.addAttributeEffect("shield_capacity", leveled(60)); 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) }) 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()); let action1 = new MoveAction(new Equipment());
nn(action1.equipment).name = "Engine"; nn(action1.equipment).name = "Engine";
action1.name = "Move"; 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"; nn(action2.equipment).name = "Weapon";
action2.name = "Fire"; action2.name = "Fire";
let action3 = new EndTurnAction(); let action3 = new EndTurnAction();

View file

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

View file

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

View file

@ -15,14 +15,14 @@ module TK.SpaceTac.UI {
mode: ActionTargettingMode mode: ActionTargettingMode
simulation = new MoveFireResult() simulation = new MoveFireResult()
// Movement projector // Move and fire lines
drawn_info: Phaser.Graphics drawn_info: Phaser.Graphics
move_ghost: Phaser.Image move_ghost: Phaser.Image
// Fire projector
fire_arrow: Phaser.Image 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 // Collaborators to update
actionbar: ActionBar actionbar: ActionBar
@ -50,17 +50,16 @@ module TK.SpaceTac.UI {
this.fire_arrow = this.view.newImage("battle-hud-simulator-ok"); this.fire_arrow = this.view.newImage("battle-hud-simulator-ok");
this.fire_arrow.anchor.set(1, 0.5); this.fire_arrow.anchor.set(1, 0.5);
this.fire_arrow.visible = false; this.fire_arrow.visible = false;
this.fire_impact = new Phaser.Group(view.game); this.impact_indicators = new Phaser.Group(view.game);
this.fire_impact.visible = false; this.impact_indicators.visible = false;
this.fire_blast = new Phaser.Image(view.game, 0, 0, "battle-arena-blast"); this.impact_area = new Phaser.Graphics(view.game);
this.fire_blast.anchor.set(0.5, 0.5); this.impact_area.visible = false;
this.fire_blast.visible = false;
this.container.add(this.fire_impact); this.container.add(this.impact_indicators);
this.container.add(this.fire_blast); this.container.add(this.impact_area);
this.container.add(this.drawn_info); this.container.add(this.drawn_info);
this.container.add(this.fire_arrow);
this.container.add(this.move_ghost); 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 { updateImpactIndicators(impacts: Phaser.Group, ship: Ship, action: BaseAction, target: Target, source: IArenaLocation = ship.location): void {
let ships: Ship[]; let ships = action.getImpactedShips(ship, target, source);
if (radius) {
let battle = ship.getBattle();
if (battle) {
ships = battle.collectShipsInCircle(target, radius, true);
} else {
ships = [];
}
} else {
ships = target.ship ? [target.ship] : [];
}
if (ships.length) { if (ships.length) {
this.fire_impact.removeAll(true); // TODO differential
impacts.removeAll(true);
ships.forEach(iship => { ships.forEach(iship => {
let indicator = this.view.newImage("battle-hud-ship-impacted", iship.arena_x, iship.arena_y); let indicator = this.view.newImage("battle-hud-ship-impacted", iship.arena_x, iship.arena_y);
indicator.anchor.set(0.5); indicator.anchor.set(0.5);
this.fire_impact.add(indicator); impacts.add(indicator);
}); });
this.fire_impact.visible = true; impacts.visible = true;
} else { } 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) { if (simulation.need_fire) {
let blast = this.action.getBlastRadius(this.ship); if (this.action instanceof TriggerAction && this.action.angle) {
if (blast) { this.impact_area.position.set(simulation.move_location.x, simulation.move_location.y);
this.fire_blast.position.set(this.target.x, this.target.y); this.impact_area.rotation = arenaAngle(simulation.move_location, simulation.fire_location);
this.fire_blast.scale.set(blast * 2 / 365);
this.fire_blast.alpha = simulation.can_fire ? 1 : 0.5;
this.fire_blast.visible = true;
} else { } 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.position.set(this.target.x, this.target.y);
this.fire_arrow.rotation = angle; this.fire_arrow.rotation = angle;
this.view.changeImage(this.fire_arrow, simulation.complete ? "battle-hud-simulator-ok" : "battle-hud-simulator-power"); this.view.changeImage(this.fire_arrow, simulation.complete ? "battle-hud-simulator-ok" : "battle-hud-simulator-power");
this.fire_arrow.visible = true; this.fire_arrow.visible = true;
} else { } else {
this.fire_blast.visible = false; this.impact_area.visible = false;
this.fire_impact.visible = false; this.impact_indicators.visible = false;
this.fire_arrow.visible = false; this.fire_arrow.visible = false;
} }
} else { } else {
@ -203,7 +229,7 @@ module TK.SpaceTac.UI {
this.fire_arrow.rotation = angle; this.fire_arrow.rotation = angle;
this.view.changeImage(this.fire_arrow, "battle-hud-simulator-failed"); this.view.changeImage(this.fire_arrow, "battle-hud-simulator-failed");
this.fire_arrow.visible = true; this.fire_arrow.visible = true;
this.fire_blast.visible = false; this.impact_area.visible = false;
} }
this.container.visible = true; this.container.visible = true;
} else { } else {
@ -270,6 +296,8 @@ module TK.SpaceTac.UI {
this.view.changeImage(this.move_ghost, `ship-${this.ship.model.code}-sprite`); this.view.changeImage(this.move_ghost, `ship-${this.ship.model.code}-sprite`);
this.move_ghost.scale.set(0.4); this.move_ghost.scale.set(0.4);
this.updateImpactArea(this.impact_area, this.action);
this.setTarget(action.getDefaultTarget(this.ship)); this.setTarget(action.getDefaultTarget(this.ship));
} else { } else {
this.ship = null; this.ship = null;

View file

@ -161,7 +161,7 @@ module TK.SpaceTac.UI {
missile.rotation = arenaAngle(this.source, this.destination); missile.rotation = arenaAngle(this.source, this.destination);
this.layer.add(missile); 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 projectile_duration = arenaDistance(this.source, this.destination) * 1.5;
let tween = this.ui.tweens.create(missile); let tween = this.ui.tweens.create(missile);
@ -185,7 +185,7 @@ module TK.SpaceTac.UI {
}); });
tween.start(); 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)) { 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)); let ships = this.arena.getShipsInCircle(new ArenaCircleArea(this.destination.x, this.destination.y, blast_radius));
ships.forEach(sprite => { ships.forEach(sprite => {

View file

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