From 3f268a3bffe5079a291ac1058de74d802be7298c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Tue, 28 Nov 2017 19:01:56 +0100 Subject: [PATCH] Fixed sticky effects not fading --- TODO.md | 1 - src/common | 2 +- src/core/ShipValue.spec.ts | 32 +++++++-- src/core/ShipValue.ts | 11 +++ src/core/actions/EndTurnAction.spec.ts | 43 ++++++++++- src/core/actions/EndTurnAction.ts | 12 +++- src/core/diffs/ShipEffectAddedDiff.ts | 6 +- src/core/diffs/ShipEffectChangedDiff.spec.ts | 76 ++++++++++++++++++++ src/core/diffs/ShipEffectChangedDiff.ts | 40 +++++++++++ src/core/effects/StickyEffect.ts | 12 +++- src/ui/battle/LogProcessor.ts | 7 +- 11 files changed, 225 insertions(+), 17 deletions(-) create mode 100644 src/core/diffs/ShipEffectChangedDiff.spec.ts diff --git a/TODO.md b/TODO.md index 10fed9f..02d3193 100644 --- a/TODO.md +++ b/TODO.md @@ -38,7 +38,6 @@ Battle ------ * Fix area effects not applying (Damage Protector) -* Fix sticky effects not fading (Power Depleter) * 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 diff --git a/src/common b/src/common index c1aa0e6..38c0670 160000 --- a/src/common +++ b/src/common @@ -1 +1 @@ -Subproject commit c1aa0e6263e9202fefc839bd97cbf16563cdca51 +Subproject commit 38c06700cfb3d03a1f7309a6200ab0ca7c0ee9d8 diff --git a/src/core/ShipValue.spec.ts b/src/core/ShipValue.spec.ts index fa16261..950b471 100644 --- a/src/core/ShipValue.spec.ts +++ b/src/core/ShipValue.spec.ts @@ -5,25 +5,43 @@ module TK.SpaceTac { check.equals(attribute.get(), 0, "initial"); attribute.addModifier(4); - check.equals(attribute.get(), 4, "added 4"); + check.in("+4", check => { + check.equals(attribute.get(), 4, "effective value"); + }); attribute.addModifier(2); - check.equals(attribute.get(), 6, "added 6"); + check.in("+4 +2", check => { + check.equals(attribute.get(), 6, "effective value"); + }); attribute.addModifier(undefined, 20); - check.equals(attribute.get(), 7, "added 20%"); + check.in("+4 +2 +20%", check => { + check.equals(attribute.get(), 7, "effective value"); + }); attribute.addModifier(undefined, 5); - check.equals(attribute.get(), 8, "added 5%"); + check.in("+4 +2 +20% +5%", check => { + check.equals(attribute.get(), 8, "effective value"); + check.equals(attribute.getMaximal(), Infinity, "maximal value"); + }); attribute.addModifier(undefined, undefined, 6); - check.equals(attribute.get(), 6, "limited to 6"); + check.in("+4 +2 +20% +5% lim6", check => { + check.equals(attribute.get(), 6, "effective value"); + check.equals(attribute.getMaximal(), 6, "maximal value"); + }); attribute.addModifier(undefined, undefined, 4); - check.equals(attribute.get(), 4, "limited to 4"); + check.in("+4 +2 +20% +5% lim6 lim4", check => { + check.equals(attribute.get(), 4, "effective value"); + check.equals(attribute.getMaximal(), 4, "maximal value"); + }); attribute.addModifier(undefined, undefined, 10); - check.equals(attribute.get(), 4, "limited to 10"); + check.in("+4 +2 +20% +5% lim6 lim4 lim10", check => { + check.equals(attribute.get(), 4, "effective value"); + check.equals(attribute.getMaximal(), 4, "maximal value"); + }); }); }); } diff --git a/src/core/ShipValue.ts b/src/core/ShipValue.ts index d00f2b9..1314ab3 100644 --- a/src/core/ShipValue.ts +++ b/src/core/ShipValue.ts @@ -58,6 +58,17 @@ module TK.SpaceTac { return this.current; } + /** + * Get the maximal value enforced by limit modifiers, Infinity for unlimited + */ + getMaximal(): number { + if (this.limits.length > 0) { + return min(this.limits); + } else { + return Infinity; + } + } + /** * Reset all modifiers */ diff --git a/src/core/actions/EndTurnAction.spec.ts b/src/core/actions/EndTurnAction.spec.ts index c51ac80..533f9dd 100644 --- a/src/core/actions/EndTurnAction.spec.ts +++ b/src/core/actions/EndTurnAction.spec.ts @@ -12,7 +12,7 @@ module TK.SpaceTac.Specs { check.equals(action.checkCannotBeApplied(battle.play_order[1]), "ship not playing"); }); - test.case("ends turn when applied", check => { + test.case("changes active ship", check => { let battle = TestTools.createBattle(2, 0); TestTools.actionChain(check, battle, [ @@ -99,5 +99,46 @@ module TK.SpaceTac.Specs { } ]); }); + + test.case("fades sticky effects for previous ship", check => { + let battle = TestTools.createBattle(1, 0); + let ship = battle.play_order[0]; + + let effect1 = new BaseEffect("e1"); + let effect2 = new StickyEffect(new AttributeLimitEffect("precision", 7), 2); + + ship.active_effects.add(effect1); + ship.active_effects.add(effect2); + effect2.base.getOnDiffs(ship, ship).forEach(effect => effect.apply(battle)); + + TestTools.actionChain(check, battle, [ + [ship, EndTurnAction.SINGLETON, Target.newFromShip(ship)], + [ship, EndTurnAction.SINGLETON, Target.newFromShip(ship)], + [ship, EndTurnAction.SINGLETON, Target.newFromShip(ship)], + ], [ + check => { + check.equals(ship.active_effects.count(), 2, "effect count"); + check.contains(ship.active_effects.ids(), effect2.id, "sticky effect active"); + check.equals((nn(ship.active_effects.get(effect2.id))).duration, 2, "duration sticky effect"); + check.equals(ship.attributes.precision.getMaximal(), 7, "max precision"); + }, + check => { + check.equals(ship.active_effects.count(), 2, "effect count"); + check.contains(ship.active_effects.ids(), effect2.id, "sticky effect active"); + check.equals((nn(ship.active_effects.get(effect2.id))).duration, 1, "duration sticky effect"); + check.equals(ship.attributes.precision.getMaximal(), 7, "max precision"); + }, + check => { + check.equals(ship.active_effects.count(), 1, "effect count"); + check.notcontains(ship.active_effects.ids(), effect2.id, "sticky effect removed"); + check.equals(ship.attributes.precision.getMaximal(), Infinity, "max precision"); + }, + check => { + check.equals(ship.active_effects.count(), 1, "effect count"); + check.notcontains(ship.active_effects.ids(), effect2.id, "sticky effect removed"); + check.equals(ship.attributes.precision.getMaximal(), Infinity, "max precision"); + } + ]); + }); }); } diff --git a/src/core/actions/EndTurnAction.ts b/src/core/actions/EndTurnAction.ts index dbb32ef..6a31064 100644 --- a/src/core/actions/EndTurnAction.ts +++ b/src/core/actions/EndTurnAction.ts @@ -27,8 +27,18 @@ module TK.SpaceTac { result.push(new ShipCooldownDiff(ship, equ, 1)); }); - // TODO sticky effects + // Fade sticky effects + iforeach(ship.active_effects.iterator(), effect => { + if (effect instanceof StickyEffect) { + if (effect.duration > 1) { + result.push(new ShipEffectChangedDiff(ship, effect, -1)); + } else { + result = result.concat(effect.getOffDiffs(ship, ship)); + } + } + }); + // Change the active ship let cycle_diff = (battle.play_order.indexOf(new_ship) == 0) ? 1 : 0; result.push(new ShipChangeDiff(ship, new_ship, cycle_diff)); diff --git a/src/core/diffs/ShipEffectAddedDiff.ts b/src/core/diffs/ShipEffectAddedDiff.ts index 2b331fa..497d655 100644 --- a/src/core/diffs/ShipEffectAddedDiff.ts +++ b/src/core/diffs/ShipEffectAddedDiff.ts @@ -11,11 +11,11 @@ module TK.SpaceTac { constructor(ship: Ship | RObjectId, effect: BaseEffect) { super(ship); - this.effect = effect; + this.effect = duplicate(effect, TK.SpaceTac); } protected applyOnShip(ship: Ship, battle: Battle): void { - ship.active_effects.add(this.effect); + ship.active_effects.add(duplicate(this.effect, TK.SpaceTac)); } protected getReverse(): BaseBattleDiff { @@ -33,7 +33,7 @@ module TK.SpaceTac { constructor(ship: Ship | RObjectId, effect: BaseEffect) { super(ship); - this.effect = effect; + this.effect = duplicate(effect, TK.SpaceTac); } protected applyOnShip(ship: Ship, battle: Battle): void { diff --git a/src/core/diffs/ShipEffectChangedDiff.spec.ts b/src/core/diffs/ShipEffectChangedDiff.spec.ts new file mode 100644 index 0000000..c46d126 --- /dev/null +++ b/src/core/diffs/ShipEffectChangedDiff.spec.ts @@ -0,0 +1,76 @@ +module TK.SpaceTac.Specs { + testing("ShipEffectChangedDiff", test => { + test.case("applies and reverts", check => { + let battle = TestTools.createBattle(); + let ship = battle.play_order[0]; + + let effect1 = new BaseEffect("e1"); + let effect2 = new StickyEffect(new BaseEffect("e2"), 2); + let effect3 = new StickyEffect(new BaseEffect("e3"), 3); + ship.active_effects.add(effect1); + ship.active_effects.add(effect2); + ship.active_effects.add(effect3); + + TestTools.diffChain(check, battle, [ + new ShipEffectChangedDiff(ship, effect1), + new ShipEffectChangedDiff(ship, effect2, -1), + new ShipEffectChangedDiff(ship, effect3, 1), + ], [ + check => { + check.equals(ship.active_effects.count(), 3, "effect count"); + check.equals(effect2.duration, 2, "duration effect2"); + check.equals(effect3.duration, 3, "duration effect3"); + }, + check => { + check.equals(ship.active_effects.count(), 3, "effect count"); + check.equals(effect2.duration, 2, "duration effect2"); + check.equals(effect3.duration, 3, "duration effect3"); + }, + check => { + check.equals(ship.active_effects.count(), 3, "effect count"); + check.equals(effect2.duration, 1, "duration effect2"); + check.equals(effect3.duration, 3, "duration effect3"); + }, + check => { + check.equals(ship.active_effects.count(), 3, "effect count"); + check.equals(effect2.duration, 1, "duration effect2"); + check.equals(effect3.duration, 4, "duration effect3"); + }, + ]); + }); + + test.case("leaves original effect untouched", check => { + let battle = TestTools.createBattle(); + let ship = battle.play_order[0]; + + let effect = new StickyEffect(new BaseEffect("effect"), 2); + let effect_at_removal = copy(effect); + effect_at_removal.duration = 1; + + TestTools.diffChain(check, battle, [ + new ShipEffectAddedDiff(ship, effect), + new ShipEffectChangedDiff(ship, effect, -1), + new ShipEffectRemovedDiff(ship, effect_at_removal), + ], [ + check => { + check.equals(ship.active_effects.count(), 0, "effect count"); + check.equals(effect.duration, 2, "original duration"); + }, + check => { + check.equals(ship.active_effects.count(), 1, "effect count"); + check.equals(effect.duration, 2, "original duration"); + check.equals((nn(ship.active_effects.get(effect.id))).duration, 2, "active duration"); + }, + check => { + check.equals(ship.active_effects.count(), 1, "effect count"); + check.equals(effect.duration, 2, "original duration"); + check.equals((nn(ship.active_effects.get(effect.id))).duration, 1, "active duration"); + }, + check => { + check.equals(ship.active_effects.count(), 0, "effect count"); + check.equals(effect.duration, 2, "original duration"); + }, + ]); + }); + }); +} \ No newline at end of file diff --git a/src/core/diffs/ShipEffectChangedDiff.ts b/src/core/diffs/ShipEffectChangedDiff.ts index e69de29..e9d8d39 100644 --- a/src/core/diffs/ShipEffectChangedDiff.ts +++ b/src/core/diffs/ShipEffectChangedDiff.ts @@ -0,0 +1,40 @@ +/// + +module TK.SpaceTac { + /** + * An effect attached to a ship changed + */ + export class ShipEffectChangedDiff extends BaseBattleShipDiff { + // Effect modified + effect: RObjectId + + // Duration diff + duration: number + + constructor(ship: Ship | RObjectId, effect: BaseEffect | RObjectId, duration = 0) { + super(ship); + + this.effect = (effect instanceof BaseEffect) ? effect.id : effect; + this.duration = duration; + } + + protected applyOnShip(ship: Ship, battle: Battle): void { + let effect = ship.active_effects.get(this.effect); + if (effect) { + if (this.duration) { + if (effect instanceof StickyEffect) { + effect.duration += this.duration; + } else { + console.error("Could not apply diff - not a sticky effect", this, ship); + } + } + } else { + console.error("Could not apply diff - effect not found on ship", this, ship); + } + } + + protected getReverse(): BaseBattleDiff { + return new ShipEffectChangedDiff(this.ship_id, this.effect, -this.duration); + } + } +} diff --git a/src/core/effects/StickyEffect.ts b/src/core/effects/StickyEffect.ts index 2d81693..55ecd16 100644 --- a/src/core/effects/StickyEffect.ts +++ b/src/core/effects/StickyEffect.ts @@ -24,7 +24,7 @@ module TK.SpaceTac { getOnDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] { // TODO if already there, remove the previous one to replace it let result: BaseBattleDiff[] = [ - new ShipEffectAddedDiff(ship, new StickyEffect(this.base, this.duration)), + new ShipEffectAddedDiff(ship, this), ] result = result.concat(this.base.getOnDiffs(ship, source)); @@ -32,6 +32,16 @@ module TK.SpaceTac { return result; } + getOffDiffs(ship: Ship, source: Ship | Drone): BaseBattleDiff[] { + let result: BaseBattleDiff[] = [ + new ShipEffectRemovedDiff(ship, this), + ] + + result = result.concat(this.base.getOffDiffs(ship, source)); + + return result; + } + isBeneficial(): boolean { return this.base.isBeneficial(); } diff --git a/src/ui/battle/LogProcessor.ts b/src/ui/battle/LogProcessor.ts index f51bdf4..124fb5a 100644 --- a/src/ui/battle/LogProcessor.ts +++ b/src/ui/battle/LogProcessor.ts @@ -14,8 +14,9 @@ module TK.SpaceTac.UI { // Forward diffs to other subscribers private forwarding: ((diff: BaseBattleDiff) => number)[] = [] - // Indicator to debug the processed logs + // Debug indicators private debug = false + private ai_disabled = false // Time at which the last action was applied private last_action: number @@ -210,8 +211,10 @@ module TK.SpaceTac.UI { if (player) { if (player.is(this.view.player)) { this.view.setInteractionEnabled(true); - } else { + } else if (!this.ai_disabled) { this.view.playAI(); + } else { + this.view.applyAction(EndTurnAction.SINGLETON); } } else { this.view.setInteractionEnabled(false);