From e13ee56581fc767475cf7d8bb91398a1925ec394 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Wed, 29 Nov 2017 01:36:07 +0100 Subject: [PATCH] Fixed area effects not applying --- TODO.md | 3 -- src/core/BattleChecks.spec.ts | 22 +++++++++++++++ src/core/BattleChecks.ts | 38 +++++++++++++++++++++++++- src/core/Ship.ts | 7 ++--- src/core/actions/EndTurnAction.spec.ts | 32 ++++++++++++++++++---- src/core/actions/EndTurnAction.ts | 4 ++- src/core/actions/ToggleAction.ts | 38 ++++++++++++++------------ src/ui/battle/Targetting.spec.ts | 2 +- src/ui/battle/Targetting.ts | 2 +- 9 files changed, 115 insertions(+), 33 deletions(-) diff --git a/TODO.md b/TODO.md index cc3c5b1..03cc3a9 100644 --- a/TODO.md +++ b/TODO.md @@ -37,8 +37,6 @@ Character sheet Battle ------ -* Fix area effects not applying (Damage Protector) -* Fix toggle actions not deactivating (Damage Protector) * Fix drone effects not applying, and drone never disappearing (Repair Drone) * Fix arena's ship hovering happening even when the character sheet (or a dialog) is open on top * Add a voluntary retreat option @@ -57,7 +55,6 @@ Battle * Allow to move targetting indicator with arrow keys * Add targetting shortcuts for "previous target", "next enemy" and "next ally" * Area targetting should include the hotkeyed ship at best (apply exclusion and power limit), not necessarily center on it -* Fix "toggle action" targetting with simulated move not activating the action after the move * Add shortcut to perform only the "move" part of a move+fire simulation * Fix delay of shield/hull impact effects (should depend on weapon animation, and ship location) * Indicate visually the power gain of "end turn" diff --git a/src/core/BattleChecks.spec.ts b/src/core/BattleChecks.spec.ts index 391cf30..873367a 100644 --- a/src/core/BattleChecks.spec.ts +++ b/src/core/BattleChecks.spec.ts @@ -44,5 +44,27 @@ module TK.SpaceTac.Specs { new ShipDeathDiff(battle, ship3), ], "2 ships to mark as dead"); }) + + test.case("fixes area effects", check => { + let battle = new Battle(); + let ship1 = battle.fleets[0].addShip(); + let ship2 = battle.fleets[1].addShip(); + let checks = new BattleChecks(battle); + + check.in("initial state", check => { + check.equals(checks.checkAreaEffects(), [], "effects diff"); + }); + + let effect1 = ship1.active_effects.add(new StickyEffect(new BaseEffect("e1"))); + let effect2 = ship1.active_effects.add(new BaseEffect("e2")); + let effect3 = ship1.active_effects.add(new BaseEffect("e3")); + check.patch(battle, "iAreaEffects", () => isingle(effect3)); + check.in("sticky+obsolete+missing", check => { + check.equals(checks.checkAreaEffects(), [ + new ShipEffectRemovedDiff(ship1, effect2), + new ShipEffectAddedDiff(ship2, effect3) + ], "effects diff"); + }); + }) }) } diff --git a/src/core/BattleChecks.ts b/src/core/BattleChecks.ts index 141bdec..4b2801a 100644 --- a/src/core/BattleChecks.ts +++ b/src/core/BattleChecks.ts @@ -40,7 +40,9 @@ module TK.SpaceTac { * This may not contain ALL the diffs needed, and should be called again while it returns diffs. */ checkAll(): BaseBattleDiff[] { - let diffs = this.checkVictory(); + let diffs: BaseBattleDiff[]; + + diffs = this.checkAreaEffects(); if (diffs.length) { return diffs; } @@ -55,6 +57,11 @@ module TK.SpaceTac { return diffs; } + diffs = this.checkVictory(); + if (diffs.length) { + return diffs; + } + return []; } @@ -112,5 +119,34 @@ module TK.SpaceTac { return result; } + + /** + * Check area effects (remove obsolete ones, and add missing ones) + */ + checkAreaEffects(): BaseBattleDiff[] { + let result: BaseBattleDiff[] = []; + + iforeach(this.battle.iships(true), ship => { + let expected = new RObjectContainer(imaterialize(this.battle.iAreaEffects(ship.arena_x, ship.arena_y))); + + // Remove obsolete effects + ship.active_effects.list().forEach(effect => { + if (!(effect instanceof StickyEffect) && !expected.get(effect.id)) { + result.push(new ShipEffectRemovedDiff(ship, effect)); + result = result.concat(effect.getOffDiffs(ship, ship)); + } + }); + + // Add missing effects + expected.list().forEach(effect => { + if (!ship.active_effects.get(effect.id)) { + result.push(new ShipEffectAddedDiff(ship, effect)); + result = result.concat(effect.getOnDiffs(ship, ship)); + } + }); + }); + + return result; + } } } diff --git a/src/core/Ship.ts b/src/core/Ship.ts index e770539..5592848 100644 --- a/src/core/Ship.ts +++ b/src/core/Ship.ts @@ -524,14 +524,13 @@ module TK.SpaceTac { /** * Iterator over all effects active for this ship. + * + * This combines the permanent effects from equipment, with sticky and area effects. */ ieffects(): Iterator { - let battle = this.getBattle(); - let area_effects = battle ? battle.iAreaEffects(this.arena_x, this.arena_y) : IEMPTY; return ichain( ichainit(imap(iarray(this.slots), slot => slot.attached ? iarray(slot.attached.effects) : IEMPTY)), - imap(this.active_effects.iterator(), effect => (effect instanceof StickyEffect) ? effect.base : effect), - area_effects + imap(this.active_effects.iterator(), effect => (effect instanceof StickyEffect) ? effect.base : effect) ); } diff --git a/src/core/actions/EndTurnAction.spec.ts b/src/core/actions/EndTurnAction.spec.ts index 533f9dd..d1736c5 100644 --- a/src/core/actions/EndTurnAction.spec.ts +++ b/src/core/actions/EndTurnAction.spec.ts @@ -37,25 +37,47 @@ module TK.SpaceTac.Specs { let battle = TestTools.createBattle(1, 0); let ship = battle.play_order[0]; TestTools.setShipAP(ship, 10, 3); + let weapon = TestTools.addWeapon(ship); + weapon.action = new ToggleAction(weapon, 2); ship.setValue("power", 6); TestTools.actionChain(check, battle, [ + [ship, weapon.action, Target.newFromShip(ship)], + [ship, weapon.action, Target.newFromShip(ship)], + [ship, EndTurnAction.SINGLETON, Target.newFromShip(ship)], + [ship, weapon.action, Target.newFromShip(ship)], [ship, EndTurnAction.SINGLETON, Target.newFromShip(ship)], [ship, EndTurnAction.SINGLETON, Target.newFromShip(ship)], + [ship, weapon.action, Target.newFromShip(ship)], [ship, EndTurnAction.SINGLETON, Target.newFromShip(ship)], ], [ check => { - check.equals(ship.getValue("power"), 6, "power=6"); + check.equals(ship.getValue("power"), 6, "power value"); }, check => { - check.equals(ship.getValue("power"), 9, "power=9"); + check.equals(ship.getValue("power"), 4, "power value"); }, check => { - check.equals(ship.getValue("power"), 10, "power=10"); + check.equals(ship.getValue("power"), 6, "power value"); }, check => { - check.equals(ship.getValue("power"), 10, "power=10"); - } + check.equals(ship.getValue("power"), 9, "power value"); + }, + check => { + check.equals(ship.getValue("power"), 7, "power value"); + }, + check => { + check.equals(ship.getValue("power"), 8, "power value"); + }, + check => { + check.equals(ship.getValue("power"), 9, "power value"); + }, + check => { + check.equals(ship.getValue("power"), 10, "power value"); + }, + check => { + check.equals(ship.getValue("power"), 10, "power value"); + }, ]); }); diff --git a/src/core/actions/EndTurnAction.ts b/src/core/actions/EndTurnAction.ts index 6a31064..0127c3f 100644 --- a/src/core/actions/EndTurnAction.ts +++ b/src/core/actions/EndTurnAction.ts @@ -20,7 +20,9 @@ module TK.SpaceTac { let new_ship = battle.getNextShip(); // Generate power - result = result.concat(ship.getValueDiffs("power", ship.getAttribute("power_generation"), true)); + let toggled_cost = isum(imap(ship.iToggleActions(true), action => action.power)); + let power_diff = ship.getAttribute("power_generation") - toggled_cost; + result = result.concat(ship.getValueDiffs("power", power_diff, true)); // Cool down equipment ship.listEquipment().filter(equ => equ.cooldown.heat > 0).forEach(equ => { diff --git a/src/core/actions/ToggleAction.ts b/src/core/actions/ToggleAction.ts index 1d493f6..b5ea14c 100644 --- a/src/core/actions/ToggleAction.ts +++ b/src/core/actions/ToggleAction.ts @@ -3,9 +3,11 @@ module TK.SpaceTac { /** * Action to toggle some effects on the ship or around it, until next turn start + * + * Toggle actions consume power when activated, and restore it when deactivated */ export class ToggleAction extends BaseAction { - // Power consumption (activation only) + // Power consumption (for activation) power: number // Effect radius @@ -37,7 +39,7 @@ module TK.SpaceTac { } getActionPointsUsage(ship: Ship, target: Target | null): number { - return this.activated ? 0 : this.power; + return this.activated ? -this.power : this.power; } getRangeRadius(ship: Ship): number { @@ -52,23 +54,25 @@ module TK.SpaceTac { return ship.is(target.ship_id) ? target : null; } - /** - * Collect the effects applied by this action - */ - getEffects(ship: Ship, target: Target, source = ship.location): [Ship, BaseEffect][] { - let result: [Ship, BaseEffect][] = []; - let ships = this.getImpactedShips(ship, target, source); - ships.forEach(ship => { - this.effects.forEach(effect => result.push([ship, effect])); - }); - return result; - } - protected getSpecificDiffs(ship: Ship, battle: Battle, target: Target): BaseBattleDiff[] { - // TODO Add effects to ships in range - return [ + let result: BaseBattleDiff[] = [ new ShipActionToggleDiff(ship, this, !this.activated) - ] + ]; + + let ships = this.getImpactedShips(ship, target, ship.location); + ships.forEach(iship => { + this.effects.forEach(effect => { + if (this.activated) { + result.push(new ShipEffectRemovedDiff(iship, effect)); + result = result.concat(effect.getOffDiffs(iship, ship)); + } else { + result.push(new ShipEffectAddedDiff(iship, effect)); + result = result.concat(effect.getOnDiffs(iship, ship)); + } + }); + }); + + return result; } getEffectsDescription(): string { diff --git a/src/ui/battle/Targetting.spec.ts b/src/ui/battle/Targetting.spec.ts index d0c7434..5bce90b 100644 --- a/src/ui/battle/Targetting.spec.ts +++ b/src/ui/battle/Targetting.spec.ts @@ -140,7 +140,7 @@ module TK.SpaceTac.UI.Specs { targetting.setAction(action, ActionTargettingMode.SURROUNDINGS); targetting.setTargetFromLocation({ x: 8000, y: 60 }); - check.equals(targetting.target, Target.newFromLocation(8000, 60), "surroundings 1"); + check.equals(targetting.target, new Target(8000, 60, playing_ship), "surroundings 1"); targetting.setTargetFromLocation({ x: playing_ship.arena_x + 10, y: playing_ship.arena_y - 20 }); check.equals(targetting.target, Target.newFromShip(playing_ship), "surroundings 2"); diff --git a/src/ui/battle/Targetting.ts b/src/ui/battle/Targetting.ts index e440b14..f4ca855 100644 --- a/src/ui/battle/Targetting.ts +++ b/src/ui/battle/Targetting.ts @@ -325,7 +325,7 @@ module TK.SpaceTac.UI { if (arenaDistance(this.ship.location, location) < 50) { this.setTarget(Target.newFromShip(this.ship)); } else { - this.setTarget(Target.newFromLocation(location.x, location.y)); + this.setTarget(new Target(location.x, location.y, this.ship)); } } else { this.setTarget(Target.newFromShip(this.ship));