From 111114e338613dbfa05a18adf33ff51eb9e93bf0 Mon Sep 17 00:00:00 2001
From: emerald000 <emerald000@hotmail.com>
Date: Sun, 3 May 2020 09:42:16 -0400
Subject: [PATCH] Refactor and add hint for "Ability resolved X times" Affects
 Ashling the Pilgrim, Inner-Flame Igniter and Soulbright Flamekin.

---
 .../src/mage/cards/a/AshlingThePilgrim.java   | 30 +++++------
 .../src/mage/cards/i/InnerFlameIgniter.java   | 46 +++-------------
 .../src/mage/cards/s/SoulbrightFlamekin.java  | 20 ++++---
 .../common/AbilityResolutionCount.java        | 39 ++++++++++++++
 .../IfAbilityHasResolvedXTimesEffect.java     | 52 +++++++++++++++++++
 .../common/AbilityResolutionCountHint.java    | 26 ++++++++++
 .../main/java/mage/game/events/GameEvent.java |  3 +-
 .../java/mage/game/stack/StackAbility.java    |  1 +
 .../common/AbilityResolvedWatcher.java        | 15 +++---
 9 files changed, 156 insertions(+), 76 deletions(-)
 create mode 100644 Mage/src/main/java/mage/abilities/dynamicvalue/common/AbilityResolutionCount.java
 create mode 100644 Mage/src/main/java/mage/abilities/effects/common/IfAbilityHasResolvedXTimesEffect.java
 create mode 100644 Mage/src/main/java/mage/abilities/hint/common/AbilityResolutionCountHint.java

diff --git a/Mage.Sets/src/mage/cards/a/AshlingThePilgrim.java b/Mage.Sets/src/mage/cards/a/AshlingThePilgrim.java
index edf24e4da5..9188c0d57e 100644
--- a/Mage.Sets/src/mage/cards/a/AshlingThePilgrim.java
+++ b/Mage.Sets/src/mage/cards/a/AshlingThePilgrim.java
@@ -6,7 +6,9 @@ import mage.abilities.common.SimpleActivatedAbility;
 import mage.abilities.costs.mana.ManaCostsImpl;
 import mage.abilities.effects.OneShotEffect;
 import mage.abilities.effects.common.DamageEverythingEffect;
+import mage.abilities.effects.common.IfAbilityHasResolvedXTimesEffect;
 import mage.abilities.effects.common.counter.AddCountersSourceEffect;
+import mage.abilities.hint.common.AbilityResolutionCountHint;
 import mage.cards.CardImpl;
 import mage.cards.CardSetInfo;
 import mage.constants.CardType;
@@ -17,7 +19,6 @@ import mage.counters.CounterType;
 import mage.filter.StaticFilters;
 import mage.game.Game;
 import mage.game.permanent.Permanent;
-import mage.players.Player;
 import mage.watchers.common.AbilityResolvedWatcher;
 
 import java.util.UUID;
@@ -40,7 +41,8 @@ public final class AshlingThePilgrim extends CardImpl {
         Ability ability = new SimpleActivatedAbility(
                 new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl("{1}{R}")
         );
-        ability.addEffect(new AshlingThePilgrimEffect());
+        ability.addEffect(new IfAbilityHasResolvedXTimesEffect(Outcome.Damage, 3, new AshlingThePilgrimEffect()));
+        ability.addHint(AbilityResolutionCountHint.instance);
         this.addAbility(ability, new AbilityResolvedWatcher());
     }
 
@@ -58,8 +60,7 @@ class AshlingThePilgrimEffect extends OneShotEffect {
 
     AshlingThePilgrimEffect() {
         super(Outcome.Damage);
-        this.staticText = "If this is the third time this ability has resolved this turn, " +
-                "remove all +1/+1 counters from {this}, and it deals that much damage to each creature and each player";
+        this.staticText = "remove all +1/+1 counters from {this}, and it deals that much damage to each creature and each player";
     }
 
     private AshlingThePilgrimEffect(final AshlingThePilgrimEffect effect) {
@@ -73,20 +74,15 @@ class AshlingThePilgrimEffect extends OneShotEffect {
 
     @Override
     public boolean apply(Game game, Ability source) {
-        Player controller = game.getPlayer(source.getControllerId());
         Permanent sourcePermanent = game.getPermanent(source.getSourceId());
-        AbilityResolvedWatcher watcher = game.getState().getWatcher(AbilityResolvedWatcher.class);
-        if (controller == null
-                || sourcePermanent == null
-                || watcher == null
-                || !watcher.checkActivations(source, game)) {
-            return false;
+        if (sourcePermanent != null) {
+            int counters = sourcePermanent.getCounters(game).getCount(CounterType.P1P1);
+            if (counters < 1) {
+                return false;
+            }
+            sourcePermanent.removeCounters(CounterType.P1P1.createInstance(counters), game);
+            return new DamageEverythingEffect(counters, StaticFilters.FILTER_PERMANENT_CREATURE).apply(game, source);
         }
-        int counters = sourcePermanent.getCounters(game).getCount(CounterType.P1P1);
-        if (counters < 1) {
-            return false;
-        }
-        sourcePermanent.removeCounters(CounterType.P1P1.createInstance(counters), game);
-        return new DamageEverythingEffect(counters, StaticFilters.FILTER_PERMANENT_CREATURE).apply(game, source);
+        return true;
     }
 }
diff --git a/Mage.Sets/src/mage/cards/i/InnerFlameIgniter.java b/Mage.Sets/src/mage/cards/i/InnerFlameIgniter.java
index 86ff0ed941..19b6a685f4 100644
--- a/Mage.Sets/src/mage/cards/i/InnerFlameIgniter.java
+++ b/Mage.Sets/src/mage/cards/i/InnerFlameIgniter.java
@@ -4,9 +4,11 @@ import mage.MageInt;
 import mage.abilities.Ability;
 import mage.abilities.common.SimpleActivatedAbility;
 import mage.abilities.costs.mana.ManaCostsImpl;
-import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.ContinuousEffect;
+import mage.abilities.effects.common.IfAbilityHasResolvedXTimesEffect;
 import mage.abilities.effects.common.continuous.BoostControlledEffect;
 import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
+import mage.abilities.hint.common.AbilityResolutionCountHint;
 import mage.abilities.keyword.FirstStrikeAbility;
 import mage.cards.CardImpl;
 import mage.cards.CardSetInfo;
@@ -15,8 +17,6 @@ import mage.constants.Duration;
 import mage.constants.Outcome;
 import mage.constants.SubType;
 import mage.filter.StaticFilters;
-import mage.game.Game;
-import mage.players.Player;
 import mage.watchers.common.AbilityResolvedWatcher;
 
 import java.util.UUID;
@@ -37,7 +37,9 @@ public final class InnerFlameIgniter extends CardImpl {
         Ability ability = new SimpleActivatedAbility(
                 new BoostControlledEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl("{2}{R}")
         );
-        ability.addEffect(new InnerFlameIgniterEffect());
+        ContinuousEffect effectIf3rdResolution = new GainAbilityControlledEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES);
+        ability.addEffect(new IfAbilityHasResolvedXTimesEffect(Outcome.AddAbility, 3, effectIf3rdResolution));
+        ability.addHint(AbilityResolutionCountHint.instance);
         this.addAbility(ability, new AbilityResolvedWatcher());
     }
 
@@ -49,38 +51,4 @@ public final class InnerFlameIgniter extends CardImpl {
     public InnerFlameIgniter copy() {
         return new InnerFlameIgniter(this);
     }
-}
-
-class InnerFlameIgniterEffect extends OneShotEffect {
-
-    InnerFlameIgniterEffect() {
-        super(Outcome.AddAbility);
-        this.staticText = "If this is the third time this ability has resolved this turn, " +
-                "creatures you control gain first strike until end of turn";
-    }
-
-    private InnerFlameIgniterEffect(final InnerFlameIgniterEffect effect) {
-        super(effect);
-    }
-
-    @Override
-    public InnerFlameIgniterEffect copy() {
-        return new InnerFlameIgniterEffect(this);
-    }
-
-    @Override
-    public boolean apply(Game game, Ability source) {
-        Player controller = game.getPlayer(source.getControllerId());
-        AbilityResolvedWatcher watcher = game.getState().getWatcher(AbilityResolvedWatcher.class);
-        if (controller == null
-                || watcher == null
-                || !watcher.checkActivations(source, game)) {
-            return false;
-        }
-        game.addEffect(new GainAbilityControlledEffect(
-                FirstStrikeAbility.getInstance(), Duration.EndOfTurn,
-                StaticFilters.FILTER_PERMANENT_CREATURE
-        ), source);
-        return true;
-    }
-}
+}
\ No newline at end of file
diff --git a/Mage.Sets/src/mage/cards/s/SoulbrightFlamekin.java b/Mage.Sets/src/mage/cards/s/SoulbrightFlamekin.java
index c4fa17cb3a..95f3198e03 100644
--- a/Mage.Sets/src/mage/cards/s/SoulbrightFlamekin.java
+++ b/Mage.Sets/src/mage/cards/s/SoulbrightFlamekin.java
@@ -6,7 +6,9 @@ import mage.abilities.Ability;
 import mage.abilities.common.SimpleActivatedAbility;
 import mage.abilities.costs.mana.ManaCostsImpl;
 import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.common.IfAbilityHasResolvedXTimesEffect;
 import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
+import mage.abilities.hint.common.AbilityResolutionCountHint;
 import mage.abilities.keyword.TrampleAbility;
 import mage.cards.CardImpl;
 import mage.cards.CardSetInfo;
@@ -37,8 +39,9 @@ public final class SoulbrightFlamekin extends CardImpl {
         Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect(
                 TrampleAbility.getInstance(), Duration.EndOfTurn
         ), new ManaCostsImpl("{2}"));
-        ability.addEffect(new SoulbrightFlamekinEffect());
+        ability.addEffect(new IfAbilityHasResolvedXTimesEffect(Outcome.PutManaInPool, 3, new SoulbrightFlamekinEffect()));
         ability.addTarget(new TargetCreaturePermanent());
+        ability.addHint(AbilityResolutionCountHint.instance);
         this.addAbility(ability, new AbilityResolvedWatcher());
     }
 
@@ -56,8 +59,7 @@ class SoulbrightFlamekinEffect extends OneShotEffect {
 
     SoulbrightFlamekinEffect() {
         super(Outcome.Damage);
-        this.staticText = "If this is the third time this ability has resolved this turn, " +
-                "you may add {R}{R}{R}{R}{R}{R}{R}{R}";
+        this.staticText = "you may add {R}{R}{R}{R}{R}{R}{R}{R}";
     }
 
     private SoulbrightFlamekinEffect(final SoulbrightFlamekinEffect effect) {
@@ -72,14 +74,10 @@ class SoulbrightFlamekinEffect extends OneShotEffect {
     @Override
     public boolean apply(Game game, Ability source) {
         Player controller = game.getPlayer(source.getControllerId());
-        AbilityResolvedWatcher watcher = game.getState().getWatcher(AbilityResolvedWatcher.class);
-        if (controller == null
-                || watcher == null
-                || !watcher.checkActivations(source, game)
-                || !controller.chooseUse(Outcome.PutManaInPool, "Add {R}{R}{R}{R}{R}{R}{R}{R}}?", source, game)) {
-            return false;
+        if (controller != null && controller.chooseUse(Outcome.PutManaInPool, "Add {R}{R}{R}{R}{R}{R}{R}{R}?", source, game)) {
+            controller.getManaPool().addMana(Mana.RedMana(8), game, source);
+            return true;
         }
-        controller.getManaPool().addMana(Mana.RedMana(8), game, source);
-        return true;
+        return false;
     }
 }
diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/AbilityResolutionCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/AbilityResolutionCount.java
new file mode 100644
index 0000000000..b2fcb80e22
--- /dev/null
+++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/AbilityResolutionCount.java
@@ -0,0 +1,39 @@
+package mage.abilities.dynamicvalue.common;
+
+import mage.abilities.Ability;
+import mage.abilities.dynamicvalue.DynamicValue;
+import mage.abilities.effects.Effect;
+import mage.game.Game;
+import mage.watchers.common.AbilityResolvedWatcher;
+
+/**
+ * @author emerald000
+ */
+public enum AbilityResolutionCount implements DynamicValue {
+
+    instance;
+
+    @Override
+    public int calculate(Game game, Ability sourceAbility, Effect effect) {
+        AbilityResolvedWatcher watcher = game.getState().getWatcher(AbilityResolvedWatcher.class);
+        if (watcher != null) {
+            return watcher.getResolutionCount(game, sourceAbility);
+        }
+        return 0;
+    }
+
+    @Override
+    public AbilityResolutionCount copy() {
+        return instance;
+    }
+
+    @Override
+    public String toString() {
+        return "X";
+    }
+
+    @Override
+    public String getMessage() {
+        return "permanents you control";
+    }
+}
diff --git a/Mage/src/main/java/mage/abilities/effects/common/IfAbilityHasResolvedXTimesEffect.java b/Mage/src/main/java/mage/abilities/effects/common/IfAbilityHasResolvedXTimesEffect.java
new file mode 100644
index 0000000000..21814f17ec
--- /dev/null
+++ b/Mage/src/main/java/mage/abilities/effects/common/IfAbilityHasResolvedXTimesEffect.java
@@ -0,0 +1,52 @@
+package mage.abilities.effects.common;
+
+import mage.abilities.Ability;
+import mage.abilities.effects.ContinuousEffect;
+import mage.abilities.effects.Effect;
+import mage.abilities.effects.OneShotEffect;
+import mage.constants.Outcome;
+import mage.game.Game;
+import mage.util.CardUtil;
+import mage.watchers.common.AbilityResolvedWatcher;
+
+/**
+ * @author emerald000
+ */
+public class IfAbilityHasResolvedXTimesEffect extends OneShotEffect {
+
+    private final int resolutionNumber;
+    private final Effect effect;
+
+    public IfAbilityHasResolvedXTimesEffect(Outcome outcome, int resolutionNumber, Effect effect) {
+        super(outcome);
+        this.resolutionNumber = resolutionNumber;
+        this.effect = effect;
+        this.staticText = "If this is the " + CardUtil.numberToOrdinalText(resolutionNumber) + " time this ability has resolved this turn, " +
+                effect.getText(null);
+    }
+
+    private IfAbilityHasResolvedXTimesEffect(final IfAbilityHasResolvedXTimesEffect effect) {
+        super(effect);
+        this.resolutionNumber = effect.resolutionNumber;
+        this.effect = effect.effect;
+    }
+
+    @Override
+    public IfAbilityHasResolvedXTimesEffect copy() {
+        return new IfAbilityHasResolvedXTimesEffect(this);
+    }
+
+    @Override
+    public boolean apply(Game game, Ability source) {
+        AbilityResolvedWatcher watcher = game.getState().getWatcher(AbilityResolvedWatcher.class);
+        if (watcher != null && watcher.getResolutionCount(game, source) == resolutionNumber) {
+            if (effect instanceof OneShotEffect) {
+                return effect.apply(game, source);
+            } else {
+                game.addEffect((ContinuousEffect) effect, source);
+                return true;
+            }
+        }
+        return true;
+    }
+}
diff --git a/Mage/src/main/java/mage/abilities/hint/common/AbilityResolutionCountHint.java b/Mage/src/main/java/mage/abilities/hint/common/AbilityResolutionCountHint.java
new file mode 100644
index 0000000000..5c44331381
--- /dev/null
+++ b/Mage/src/main/java/mage/abilities/hint/common/AbilityResolutionCountHint.java
@@ -0,0 +1,26 @@
+package mage.abilities.hint.common;
+
+import mage.abilities.Ability;
+import mage.abilities.dynamicvalue.common.AbilityResolutionCount;
+import mage.abilities.hint.Hint;
+import mage.abilities.hint.ValueHint;
+import mage.game.Game;
+
+/**
+ * @author emerald000
+ */
+public enum AbilityResolutionCountHint implements Hint {
+
+    instance;
+    private static final Hint hint = new ValueHint("Resolution count:", AbilityResolutionCount.instance);
+
+    @Override
+    public String getText(Game game, Ability ability) {
+        return hint.getText(game, ability);
+    }
+
+    @Override
+    public Hint copy() {
+        return instance;
+    }
+}
diff --git a/Mage/src/main/java/mage/game/events/GameEvent.java b/Mage/src/main/java/mage/game/events/GameEvent.java
index cad89d63a9..171da25007 100644
--- a/Mage/src/main/java/mage/game/events/GameEvent.java
+++ b/Mage/src/main/java/mage/game/events/GameEvent.java
@@ -150,7 +150,8 @@ public class GameEvent implements Serializable {
         SPELL_CAST,
         ACTIVATE_ABILITY, ACTIVATED_ABILITY,
         TRIGGERED_ABILITY,
-        COPY_STACKOBJECT,COPIED_STACKOBJECT,
+        RESOLVED_ABILITY,
+        COPY_STACKOBJECT, COPIED_STACKOBJECT,
         /* ADD_MANA
          targetId    id of the ability that added the mana
          sourceId    sourceId of the ability that added the mana
diff --git a/Mage/src/main/java/mage/game/stack/StackAbility.java b/Mage/src/main/java/mage/game/stack/StackAbility.java
index cb4149bcfe..b35a664bb2 100644
--- a/Mage/src/main/java/mage/game/stack/StackAbility.java
+++ b/Mage/src/main/java/mage/game/stack/StackAbility.java
@@ -82,6 +82,7 @@ public class StackAbility extends StackObjImpl implements Ability {
     @Override
     public boolean resolve(Game game) {
         if (ability.getTargets().stillLegal(ability, game) || !canFizzle()) {
+            game.fireEvent(new GameEvent(GameEvent.EventType.RESOLVED_ABILITY, ability.getOriginalId(), ability.getSourceId(), ability.getControllerId()));
             boolean result = ability.resolve(game);
             game.getStack().remove(this, game);
             return result;
diff --git a/Mage/src/main/java/mage/watchers/common/AbilityResolvedWatcher.java b/Mage/src/main/java/mage/watchers/common/AbilityResolvedWatcher.java
index ccb1f75c81..dfa3d5daab 100644
--- a/Mage/src/main/java/mage/watchers/common/AbilityResolvedWatcher.java
+++ b/Mage/src/main/java/mage/watchers/common/AbilityResolvedWatcher.java
@@ -1,6 +1,5 @@
 package mage.watchers.common;
 
-import mage.MageObjectReference;
 import mage.abilities.Ability;
 import mage.constants.WatcherScope;
 import mage.game.Game;
@@ -9,14 +8,13 @@ import mage.watchers.Watcher;
 
 import java.util.HashMap;
 import java.util.Map;
-import java.util.UUID;
 
 /**
  * @author TheElk801
  */
 public class AbilityResolvedWatcher extends Watcher {
 
-    private final Map<MageObjectReference, Map<UUID, Integer>> activationMap = new HashMap<>();
+    private final Map<String, Integer> resolutionMap = new HashMap<>();
 
     public AbilityResolvedWatcher() {
         super(WatcherScope.GAME);
@@ -24,17 +22,18 @@ public class AbilityResolvedWatcher extends Watcher {
 
     @Override
     public void watch(GameEvent event, Game game) {
+        if (event.getType() == GameEvent.EventType.RESOLVED_ABILITY) {
+            resolutionMap.merge(event.getTargetId().toString() + game.getState().getZoneChangeCounter(event.getSourceId()), 1, Integer::sum);
+        }
     }
 
     @Override
     public void reset() {
         super.reset();
-        activationMap.clear();
+        resolutionMap.clear();
     }
 
-    public boolean checkActivations(Ability source, Game game) {
-        return activationMap.computeIfAbsent(new MageObjectReference(
-                source.getSourceId(), source.getSourceObjectZoneChangeCounter(), game
-        ), x -> new HashMap<>()).compute(source.getOriginalId(), (u, i) -> i == null ? 1 : i + 1).intValue() == 3;
+    public int getResolutionCount(Game game, Ability source) {
+        return resolutionMap.getOrDefault(source.getOriginalId().toString() + game.getState().getZoneChangeCounter(source.getSourceId()), 0);
     }
 }