diff --git a/Mage.Sets/src/mage/sets/commander2014/AngelOfTheDireHour.java b/Mage.Sets/src/mage/sets/commander2014/AngelOfTheDireHour.java index 40d5609c621..04336e553d5 100644 --- a/Mage.Sets/src/mage/sets/commander2014/AngelOfTheDireHour.java +++ b/Mage.Sets/src/mage/sets/commander2014/AngelOfTheDireHour.java @@ -29,10 +29,9 @@ package mage.sets.commander2014; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromHandCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.ExileAllEffect; import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.FlyingAbility; @@ -61,10 +60,11 @@ public class AngelOfTheDireHour extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // When Angel of the Dire Hour enters the battlefield, if you cast it from your hand, exile all attacking creatures. - Ability ability = new EntersBattlefieldTriggeredAbility( - new ConditionalOneShotEffect(new ExileAllEffect(new FilterAttackingCreature("attacking creatures")), new CastFromHandCondition(), - " if you cast it from your hand, exile all attacking creatures")); - this.addAbility(ability, new CastFromHandWatcher()); + this.addAbility(new ConditionalTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new ExileAllEffect(new FilterAttackingCreature("attacking creatures")), false), + new CastFromHandCondition(), + "When {this} enters the battlefield, if you cast it from your hand, exile all attacking creatures."), + new CastFromHandWatcher()); } public AngelOfTheDireHour(final AngelOfTheDireHour card) { diff --git a/Mage.Sets/src/mage/sets/commander2014/BreachingLeviathan.java b/Mage.Sets/src/mage/sets/commander2014/BreachingLeviathan.java index 9e814341154..e8e24c4d57c 100644 --- a/Mage.Sets/src/mage/sets/commander2014/BreachingLeviathan.java +++ b/Mage.Sets/src/mage/sets/commander2014/BreachingLeviathan.java @@ -33,7 +33,7 @@ import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromHandCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; @@ -64,10 +64,11 @@ public class BreachingLeviathan extends CardImpl { this.toughness = new MageInt(9); // When Breaching Leviathan enters the battlefield, if you cast it from your hand, tap all nonblue creatures. Those creatures don't untap during their controllers' next untap steps. - Ability ability = new EntersBattlefieldTriggeredAbility( - new ConditionalOneShotEffect(new BreachingLeviathanEffect(), new CastFromHandCondition(), - "if you cast it from your hand, tap all nonblue creatures. Those creatures don't untap during their controllers' next untap steps")); - this.addAbility(ability, new CastFromHandWatcher()); + this.addAbility(new ConditionalTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new BreachingLeviathanEffect(), false), + new CastFromHandCondition(), + "When {this} enters the battlefield, if you cast it from your hand, tap all nonblue creatures. Those creatures don't untap during their controllers' next untap steps."), + new CastFromHandWatcher()); } public BreachingLeviathan(final BreachingLeviathan card) { @@ -104,7 +105,7 @@ class BreachingLeviathanEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Permanent creature: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { creature.tap(game); ContinuousEffect effect = new DontUntapInControllersNextUntapStepTargetEffect(); effect.setTargetPointer(new FixedTarget(creature.getId())); diff --git a/Mage.Sets/src/mage/sets/darksteel/FurnaceDragon.java b/Mage.Sets/src/mage/sets/darksteel/FurnaceDragon.java index 8c7f749d57b..0e9d02637b8 100644 --- a/Mage.Sets/src/mage/sets/darksteel/FurnaceDragon.java +++ b/Mage.Sets/src/mage/sets/darksteel/FurnaceDragon.java @@ -29,10 +29,9 @@ package mage.sets.darksteel; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.condition.common.CastFromHandCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.ExileAllEffect; import mage.abilities.keyword.AffinityForArtifactsAbility; import mage.abilities.keyword.FlyingAbility; @@ -41,9 +40,6 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.watchers.Watcher; import mage.watchers.common.CastFromHandWatcher; /** @@ -51,7 +47,7 @@ import mage.watchers.common.CastFromHandWatcher; * @author fireshoes */ public class FurnaceDragon extends CardImpl { - + private static final FilterPermanent filter = new FilterPermanent("artifacts"); static { @@ -67,12 +63,16 @@ public class FurnaceDragon extends CardImpl { // Affinity for artifacts this.addAbility(new AffinityForArtifactsAbility()); - + // Flying this.addAbility(FlyingAbility.getInstance()); - + // When Furnace Dragon enters the battlefield, if you cast it from your hand, exile all artifacts. - this.addAbility(new EntersBattlefieldTriggeredAbility(new ConditionalOneShotEffect(new ExileAllEffect(filter), new FurnaceDragonCondition()), false), new CastFromHandWatcher()); + this.addAbility(new ConditionalTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new ExileAllEffect(filter), false), + new CastFromHandCondition(), + "When {this} enters the battlefield, if you cast it from your hand, exile all artifacts."), + new CastFromHandWatcher()); } public FurnaceDragon(final FurnaceDragon card) { @@ -84,24 +84,3 @@ public class FurnaceDragon extends CardImpl { return new FurnaceDragon(this); } } - -class FurnaceDragonCondition implements Condition { - - @Override - public boolean apply(Game game, Ability source) { - boolean applies = false; - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - Watcher watcher = game.getState().getWatchers().get("CastFromHand", source.getSourceId()); - if (watcher != null && watcher.conditionMet()) { - applies = true; - } - } - return applies; - } - - @Override - public String toString() { - return "you cast it from your hand"; - } -} diff --git a/Mage.Sets/src/mage/sets/divinevsdemonic/ReiverDemon.java b/Mage.Sets/src/mage/sets/divinevsdemonic/ReiverDemon.java index 92b37c9990c..1278473e692 100644 --- a/Mage.Sets/src/mage/sets/divinevsdemonic/ReiverDemon.java +++ b/Mage.Sets/src/mage/sets/divinevsdemonic/ReiverDemon.java @@ -30,10 +30,9 @@ package mage.sets.divinevsdemonic; import java.util.UUID; import mage.MageInt; import mage.ObjectColor; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromHandCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -50,9 +49,9 @@ import mage.watchers.common.CastFromHandWatcher; * @author daagar */ public class ReiverDemon extends CardImpl { - + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonartifact, nonblack creatures"); - + static { filter.add(Predicates.not(new CardTypePredicate(CardType.ARTIFACT))); filter.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK))); @@ -67,12 +66,13 @@ public class ReiverDemon extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // When Reiver Demon enters the battlefield, if you cast it from your hand, destroy all nonartifact, nonblack creatures. They can't be regenerated. - Ability ability = new EntersBattlefieldTriggeredAbility( - new ConditionalOneShotEffect(new DestroyAllEffect(filter), new CastFromHandCondition(), - "if you cast it from your hand, destroy all nonartifact, nonblack creatures. They can't be regenerated")); - this.addAbility(ability, new CastFromHandWatcher()); + this.addAbility(new ConditionalTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(filter, true), false), + new CastFromHandCondition(), + "When {this} enters the battlefield, if you cast it from your hand, destroy all nonartifact, nonblack creatures. They can't be regenerated."), + new CastFromHandWatcher()); } public ReiverDemon(final ReiverDemon card) { diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/DeathbringerRegent.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/DeathbringerRegent.java index e7da53ee3e6..b4b5e194f9c 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/DeathbringerRegent.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/DeathbringerRegent.java @@ -32,7 +32,8 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.condition.common.CastFromHandCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -41,8 +42,6 @@ import mage.constants.Rarity; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AnotherPredicate; import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.watchers.Watcher; import mage.watchers.common.CastFromHandWatcher; /** @@ -50,9 +49,9 @@ import mage.watchers.common.CastFromHandWatcher; * @author jeffwadsworth */ public class DeathbringerRegent extends CardImpl { - + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other creatures"); - + static { filter.add(new AnotherPredicate()); } @@ -66,10 +65,13 @@ public class DeathbringerRegent extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // When Deathbringer Regent enters the battlefield, if you cast it from your hand and there are five or more other creatures on the battlefield, destroy all other creatures. - this.addAbility(new EntersBattlefieldTriggeredAbility(new ConditionalOneShotEffect(new DestroyAllEffect(filter), new DeathbringerRegentCondition()), false), new CastFromHandWatcher()); - + this.addAbility(new ConditionalTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(filter), false), + new DeathbringerRegentCondition(), + "When {this} enters the battlefield, if you cast it from your hand and there are five or more other creatures on the battlefield, destroy all other creatures."), + new CastFromHandWatcher()); } public DeathbringerRegent(final DeathbringerRegent card) { @@ -86,22 +88,7 @@ class DeathbringerRegentCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - boolean applies = false; - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - Watcher watcher = game.getState().getWatchers().get("CastFromHand", source.getSourceId()); - if (watcher != null && watcher.conditionMet()) { - applies = true; - } - } - if (applies) { - applies = game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), game).size() >= 6; - } - return applies; + return new CastFromHandCondition().apply(game, source) + && game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), game).size() >= 6; } - - @Override - public String toString() { - return "you cast it from your hand and there are five or more other creatures on the battlefield"; - } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/InameAsOne.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/InameAsOne.java index ddb5f7a790f..769130d982f 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/InameAsOne.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/InameAsOne.java @@ -34,7 +34,7 @@ import mage.abilities.Ability; import mage.abilities.common.DiesTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromHandCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileSourceEffect; @@ -75,13 +75,14 @@ public class InameAsOne extends CardImpl { this.toughness = new MageInt(8); // When Iname as One enters the battlefield, if you cast it from your hand, you may search your library for a Spirit permanent card, put it onto the battlefield, then shuffle your library. - Ability ability = new EntersBattlefieldTriggeredAbility( - new ConditionalOneShotEffect(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(0, 1, filter), false), - new CastFromHandCondition())); - this.addAbility(ability, new CastFromHandWatcher()); + this.addAbility(new ConditionalTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(0, 1, filter)), true), + new CastFromHandCondition(), + "When {this} enters the battlefield, if you cast it from your hand, you may search your library for a Spirit permanent card, put it onto the battlefield, then shuffle your library."), + new CastFromHandWatcher()); // When Iname as One dies, you may exile it. If you do, return target Spirit permanent card from your graveyard to the battlefield. - ability = new DiesTriggeredAbility(new InameAsOneEffect(), false); + Ability ability = new DiesTriggeredAbility(new InameAsOneEffect(), false); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/sorinvstibalt/CoalStoker.java b/Mage.Sets/src/mage/sets/sorinvstibalt/CoalStoker.java index 85b2aa32175..403d9c7a95c 100644 --- a/Mage.Sets/src/mage/sets/sorinvstibalt/CoalStoker.java +++ b/Mage.Sets/src/mage/sets/sorinvstibalt/CoalStoker.java @@ -30,16 +30,13 @@ package mage.sets.sorinvstibalt; import java.util.UUID; import mage.MageInt; import mage.Mana; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromHandCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.BasicManaEffect; -import mage.abilities.effects.common.ExileAllEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; -import mage.filter.common.FilterAttackingCreature; import mage.watchers.common.CastFromHandWatcher; /** @@ -56,10 +53,11 @@ public class CoalStoker extends CardImpl { this.toughness = new MageInt(3); // When Coal Stoker enters the battlefield, if you cast it from your hand, add {R}{R}{R} to your mana pool. - Ability ability = new EntersBattlefieldTriggeredAbility( - new ConditionalOneShotEffect(new BasicManaEffect(new Mana(3, 0, 0, 0, 0, 0, 0, 0)), new CastFromHandCondition(), - " if you cast it from your hand, add {R}{R}{R} to your mana pool.")); - this.addAbility(ability, new CastFromHandWatcher()); + this.addAbility(new ConditionalTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new BasicManaEffect(new Mana(3, 0, 0, 0, 0, 0, 0, 0)), false), + new CastFromHandCondition(), + "When {this} enters the battlefield, if you cast it from your hand, add {R}{R}{R} to your mana pool."), + new CastFromHandWatcher()); } public CoalStoker(final CoalStoker card) { diff --git a/Mage/src/main/java/mage/abilities/condition/common/CastFromHandCondition.java b/Mage/src/main/java/mage/abilities/condition/common/CastFromHandCondition.java index 069f7367160..8c36bb8bb61 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/CastFromHandCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/CastFromHandCondition.java @@ -6,7 +6,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.stack.Spell; -import mage.watchers.Watcher; +import mage.watchers.common.CastFromHandWatcher; /** * Warning: CastFromHandWatcher must be installed to card for proper working. @@ -31,9 +31,8 @@ public class CastFromHandCondition implements Condition { return false; } } - // Probably watcher is no longer needed - Watcher watcher = game.getState().getWatchers().get("CastFromHand", source.getSourceId()); - if (watcher != null && watcher.conditionMet()) { + CastFromHandWatcher watcher = (CastFromHandWatcher) game.getState().getWatchers().get(CastFromHandWatcher.class.getName(), source.getSourceId()); + if (watcher != null && watcher.spellWasCastFromHand(source.getSourceId()) { return true; } } diff --git a/Mage/src/main/java/mage/watchers/common/CastFromHandWatcher.java b/Mage/src/main/java/mage/watchers/common/CastFromHandWatcher.java index 3aee2d79fd8..805423c19fb 100644 --- a/Mage/src/main/java/mage/watchers/common/CastFromHandWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CastFromHandWatcher.java @@ -1,15 +1,23 @@ package mage.watchers.common; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; import mage.constants.WatcherScope; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.Spell; +import mage.game.turn.Step; import mage.watchers.Watcher; public class CastFromHandWatcher extends Watcher { + + private final Set spellsCastFromHand = new HashSet<>(); + private Step step; + public CastFromHandWatcher() { - super("CastFromHand", WatcherScope.CARD); + super(CastFromHandWatcher.class.getName(), WatcherScope.GAME); } public CastFromHandWatcher(final CastFromHandWatcher watcher) { @@ -18,14 +26,35 @@ public class CastFromHandWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.SPELL_CAST && event.getZone() == Zone.HAND) { + /** + * This does still not handle if a spell is cast from hand and comes to + * play from other zones during the same step. But at least the state is + * reset if the game comes to a new step + */ + + if (step != null && game.getTurn().getStep() != step) { + spellsCastFromHand.clear(); + step = null; + } + if (event.getType() == GameEvent.EventType.SPELL_CAST && event.getZone().equals(Zone.HAND)) { + step = game.getTurn().getStep(); Spell spell = (Spell) game.getObject(event.getTargetId()); if (this.getSourceId().equals(spell.getSourceId())) { - condition = true; + condition = true; } } } + public boolean spellWasCastFromHand(UUID sourceId) { + return spellsCastFromHand.contains(sourceId); + } + + @Override + public void reset() { + super.reset(); + spellsCastFromHand.clear(); + } + @Override public CastFromHandWatcher copy() { return new CastFromHandWatcher(this);