diff --git a/Mage.Sets/src/mage/cards/a/AetherfluxReservoir.java b/Mage.Sets/src/mage/cards/a/AetherfluxReservoir.java index 871b4d90ac6..ae9adf70a80 100644 --- a/Mage.Sets/src/mage/cards/a/AetherfluxReservoir.java +++ b/Mage.Sets/src/mage/cards/a/AetherfluxReservoir.java @@ -10,6 +10,7 @@ import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.hint.ValueHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -28,12 +29,14 @@ public final class AetherfluxReservoir extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); // Whenever you cast a spell, you gain 1 life for each spell you've cast this turn. - this.addAbility(new SpellCastControllerTriggeredAbility(new GainLifeEffect(new AetherfluxReservoirDynamicValue()), false)); + Ability abilityGainLife = new SpellCastControllerTriggeredAbility(new GainLifeEffect(new AetherfluxReservoirDynamicValue()), false); + abilityGainLife.addHint(new ValueHint("You've cast spells this turn", new AetherfluxReservoirDynamicValue())); + this.addAbility(abilityGainLife); // Pay 50 life: Aetherflux Reservoir deals 50 damage to any target. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(50), new PayLifeCost(50)); - ability.addTarget(new TargetAnyTarget()); - this.addAbility(ability); + Ability abilityPayLife = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(50), new PayLifeCost(50)); + abilityPayLife.addTarget(new TargetAnyTarget()); + this.addAbility(abilityPayLife); } public AetherfluxReservoir(final AetherfluxReservoir card) { diff --git a/Mage.Sets/src/mage/cards/s/SentinelTower.java b/Mage.Sets/src/mage/cards/s/SentinelTower.java index be47a83810a..398c5b42049 100644 --- a/Mage.Sets/src/mage/cards/s/SentinelTower.java +++ b/Mage.Sets/src/mage/cards/s/SentinelTower.java @@ -2,10 +2,13 @@ package mage.cards.s; import mage.MageObject; import mage.MageObjectReference; +import mage.abilities.Ability; import mage.abilities.common.SpellCastAllTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.hint.ValueHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -44,13 +47,18 @@ public final class SentinelTower extends CardImpl { class SentinelTowerTriggeredAbility extends SpellCastAllTriggeredAbility { + private String damageInfo; + SentinelTowerTriggeredAbility() { super(new DamageTargetEffect(0), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false); this.addTarget(new TargetAnyTarget()); + this.addHint(new ValueHint("There were cast instant and sorcery this turn", SentinelTowerSpellsCastValue.instance)); + this.damageInfo = null; } SentinelTowerTriggeredAbility(final SentinelTowerTriggeredAbility effect) { super(effect); + this.damageInfo = effect.damageInfo; } @Override @@ -78,6 +86,7 @@ class SentinelTowerTriggeredAbility extends SpellCastAllTriggeredAbility { break; } } + damageInfo = " (" + damageToDeal + " damage)"; for (Effect effect : this.getEffects()) { if (effect instanceof DamageTargetEffect) { ((DamageTargetEffect) effect).setAmount(StaticValue.get(damageToDeal)); @@ -92,7 +101,8 @@ class SentinelTowerTriggeredAbility extends SpellCastAllTriggeredAbility { public String getRule() { return "Whenever an instant or sorcery spell is cast during your turn, " + "{this} deals damage to any target equal to 1 " - + "plus the number of instant and sorcery spells cast before that spell this turn."; + + "plus the number of instant and sorcery spells cast before that spell this turn." + + (damageInfo != null ? damageInfo : ""); } } @@ -124,3 +134,36 @@ class SentinelTowerWatcher extends Watcher { return spellsThisTurn; } } + +enum SentinelTowerSpellsCastValue implements DynamicValue { + + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + SentinelTowerWatcher watcher = game.getState().getWatcher(SentinelTowerWatcher.class); + if (watcher == null) { + return 0; + } + List spellsCast = watcher.getSpellsThisTurn(); + if (spellsCast == null) { + return 0; + } + return spellsCast.size(); + } + + @Override + public SentinelTowerSpellsCastValue copy() { + return instance; + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return "There was an instant or sorcery spell in this turn"; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/ThousandYearStorm.java b/Mage.Sets/src/mage/cards/t/ThousandYearStorm.java index 1fd0f08a6ea..99e954fd147 100644 --- a/Mage.Sets/src/mage/cards/t/ThousandYearStorm.java +++ b/Mage.Sets/src/mage/cards/t/ThousandYearStorm.java @@ -1,5 +1,7 @@ package mage.cards.t; +import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.SpellCastControllerTriggeredAbility; @@ -13,7 +15,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.WatcherScope; import mage.constants.Zone; -import mage.filter.common.FilterInstantOrSorcerySpell; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.Spell; @@ -23,9 +25,11 @@ import mage.watchers.Watcher; import java.util.HashMap; import java.util.Map; import java.util.UUID; +import java.util.List; +import java.util.ArrayList; /** - * @author LevelX2 + * @author jasc7636 */ public final class ThousandYearStorm extends CardImpl { @@ -33,7 +37,7 @@ public final class ThousandYearStorm extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{U}{R}"); // Whenever you cast an instant or sorcery spell, copy it for each other instant and sorcery spell you've cast before it this turn. You may choose new targets for the copies. - this.addAbility(new ThousandYearStormAbility()); + this.addAbility(new ThousandYearStormAbility(), new ThousandYearStormWatcher()); } public ThousandYearStorm(final ThousandYearStorm card) { @@ -48,12 +52,12 @@ public final class ThousandYearStorm extends CardImpl { class ThousandYearStormAbility extends SpellCastControllerTriggeredAbility { - String stormCountInfo = null; + private String stormCountInfo; public ThousandYearStormAbility() { - super(Zone.BATTLEFIELD, new ThousandYearStormEffect(), new FilterInstantOrSorcerySpell(), false, true); - this.addHint(new ValueHint("You've cast instant and sorcery this turn", ThousandYearSpellsCastThatTurnValue.instance)); - this.addWatcher(new ThousandYearWatcher()); + super(Zone.BATTLEFIELD, new ThousandYearStormEffect(), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false, true); + this.addHint(new ValueHint("You've cast instant and sorcery this turn", ThousandYearStormSpellsCastThatTurnValue.instance)); + this.stormCountInfo = null; } public ThousandYearStormAbility(final ThousandYearStormAbility ability) { @@ -63,11 +67,32 @@ class ThousandYearStormAbility extends SpellCastControllerTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - // save storm count info, real count will be calculated to stack ability in resolve effect only if (super.checkTrigger(event, game)) { - int stormCount = ThousandYearSpellsCastThatTurnValue.instance.calculate(game, this, null); - stormCountInfo = " (storm count: " + Math.max(0, stormCount - 1) + ") "; - return true; + ThousandYearStormWatcher watcher = game.getState().getWatcher(ThousandYearStormWatcher.class); + if (watcher == null) { + return false; + } + UUID playerId = event.getPlayerId(); + List spellsCast = watcher.getSpellsThisTurn(playerId); + MageObject object = game.getObject(event.getTargetId()); + if (object == null || spellsCast == null) { + return false; + } + int stormCount = 0; + for (MageObjectReference mor : spellsCast) { + stormCount++; + if (mor.refersTo(object, game)) { + break; + } + } + stormCount = Math.max(0, stormCount - 1); + stormCountInfo = " (storm count: " + stormCount + ") "; + for (Effect effect : this.getEffects()) { + if (effect instanceof ThousandYearStormEffect) { + ((ThousandYearStormEffect) effect).setStormCount(stormCount); + return true; + } + } } return false; } @@ -85,13 +110,16 @@ class ThousandYearStormAbility extends SpellCastControllerTriggeredAbility { } class ThousandYearStormEffect extends OneShotEffect { + private int stormCount; public ThousandYearStormEffect() { super(Outcome.Benefit); + this.stormCount = -1; } public ThousandYearStormEffect(final ThousandYearStormEffect effect) { super(effect); + this.stormCount = effect.stormCount; } @Override @@ -102,82 +130,72 @@ class ThousandYearStormEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Spell spell = game.getSpellOrLKIStack(getTargetPointer().getFirst(game, source)); - Player controller = spell != null ? game.getPlayer(spell.getControllerId()) : null; - if (spell != null && controller != null) { - ThousandYearWatcher watcher = game.getState().getWatcher(ThousandYearWatcher.class); - if (watcher != null) { - String stateSearchId = spell.getId().toString() + source.getSourceId().toString(); - // recall only the spells cast before it - int numberOfCopies = 0; - if (game.getState().getValue(stateSearchId) != null) { - numberOfCopies = (int) game.getState().getValue(stateSearchId); - } - if (numberOfCopies > 0) { - spell.createCopyOnStack(game, source, source.getControllerId(), true, numberOfCopies); - } - return true; - } + if (stormCount >= 0 && spell != null) { + spell.createCopyOnStack(game, source, source.getControllerId(), true, stormCount); + return true; } return false; } + public void setStormCount(int stormCount) { + this.stormCount = stormCount; + } + @Override public String getText(Mode mode) { return "copy it for each other instant and sorcery spell you've cast before it this turn. You may choose new targets for the copies"; } } -class ThousandYearWatcher extends Watcher { +class ThousandYearStormWatcher extends Watcher { - private final Map amountOfInstantSorcerySpellsCastOnCurrentTurn = new HashMap<>(); + private final Map> spellsThisTurn = new HashMap<>(); - public ThousandYearWatcher() { + public ThousandYearStormWatcher() { super(WatcherScope.GAME); } @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.SPELL_CAST && !sourceId.equals(event.getTargetId())) { - Spell spell = game.getSpellOrLKIStack(event.getTargetId()); - if (spell != null && spell.isInstantOrSorcery()) { + if (event.getType() == GameEvent.EventType.SPELL_CAST) { + MageObject object = game.getObject(event.getTargetId()); + if (object != null && (object.isInstant() || object.isSorcery())) { UUID playerId = event.getPlayerId(); - if (playerId != null) { - String stateSearchId = spell.getId().toString() + sourceId.toString(); - // calc current spell - amountOfInstantSorcerySpellsCastOnCurrentTurn.putIfAbsent(playerId, 0); - amountOfInstantSorcerySpellsCastOnCurrentTurn.compute(playerId, (k, a) -> a + 1); - // remember only the spells cast before it - game.getState().setValue(stateSearchId, amountOfInstantSorcerySpellsCastOnCurrentTurn.get(playerId) - 1); - } + List spellsCast = spellsThisTurn.getOrDefault(playerId, new ArrayList()); + spellsCast.add(new MageObjectReference(object, game)); + spellsThisTurn.put(playerId, spellsCast); } } } @Override public void reset() { - amountOfInstantSorcerySpellsCastOnCurrentTurn.clear(); + for (List mor : spellsThisTurn.values()) { + mor.clear(); + } + spellsThisTurn.clear(); } - public int getAmountOfSpellsPlayerCastOnCurrentTurn(UUID playerId) { - return amountOfInstantSorcerySpellsCastOnCurrentTurn.getOrDefault(playerId, 0); + public List getSpellsThisTurn(UUID playerId) { + return spellsThisTurn.getOrDefault(playerId, new ArrayList()); } } -enum ThousandYearSpellsCastThatTurnValue implements DynamicValue { +enum ThousandYearStormSpellsCastThatTurnValue implements DynamicValue { instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - ThousandYearWatcher watcher = game.getState().getWatcher(ThousandYearWatcher.class); + ThousandYearStormWatcher watcher = game.getState().getWatcher(ThousandYearStormWatcher.class); if (watcher == null) { return 0; } - return watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(sourceAbility.getControllerId()); + return watcher.getSpellsThisTurn(sourceAbility.getControllerId()).size(); } @Override - public ThousandYearSpellsCastThatTurnValue copy() { + public ThousandYearStormSpellsCastThatTurnValue copy() { return instance; }