diff --git a/Mage.Sets/src/mage/cards/m/MisterFantastic.java b/Mage.Sets/src/mage/cards/m/MisterFantastic.java new file mode 100644 index 00000000000..078d6278575 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MisterFantastic.java @@ -0,0 +1,87 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.CastNoncreatureSpellThisTurnCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CopyTargetStackObjectEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.ReachAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.TargetController; +import mage.filter.FilterStackObject; +import mage.filter.predicate.Predicate; +import mage.game.Game; +import mage.game.stack.StackObject; +import mage.target.TargetStackObject; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MisterFantastic extends CardImpl { + + private static final FilterStackObject filter = new FilterStackObject("triggered ability you control"); + + static { + filter.add(MisterFantasticPredicate.instance); + filter.add(TargetController.YOU.getControllerPredicate()); + } + + public MisterFantastic(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SCIENTIST); + this.subtype.add(SubType.HERO); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // At the beginning of combat on your turn, if you've cast a noncreature spell this turn, draw a card. + this.addAbility(new BeginningOfCombatTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(CastNoncreatureSpellThisTurnCondition.instance) + .addHint(CastNoncreatureSpellThisTurnCondition.getHint())); + + // {R}{G}{W}{U}, {T}: Copy target triggered ability you control twice. You may choose new targets for the copies. + Ability ability = new SimpleActivatedAbility(new CopyTargetStackObjectEffect() + .setText("copy target triggered ability you control twice"), new ManaCostsImpl<>("{R}{G}{W}{U}")); + ability.addCost(new TapSourceCost()); + ability.addEffect(new CopyTargetStackObjectEffect().setText("You may choose new targets for the copies.")); + ability.addTarget(new TargetStackObject(filter)); + this.addAbility(ability); + } + + private MisterFantastic(final MisterFantastic card) { + super(card); + } + + @Override + public MisterFantastic copy() { + return new MisterFantastic(this); + } +} + +enum MisterFantasticPredicate implements Predicate { + instance; + + @Override + public boolean apply(StackObject input, Game game) { + return input instanceof Ability && ((Ability) input).isTriggeredAbility(); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SeekerOfInsight.java b/Mage.Sets/src/mage/cards/s/SeekerOfInsight.java index 5a5b24a3247..f8afb4c2a63 100644 --- a/Mage.Sets/src/mage/cards/s/SeekerOfInsight.java +++ b/Mage.Sets/src/mage/cards/s/SeekerOfInsight.java @@ -1,17 +1,14 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CastNoncreatureSpellThisTurnCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.Game; -import mage.watchers.common.SpellsCastWatcher; import java.util.UUID; @@ -30,8 +27,8 @@ public final class SeekerOfInsight extends CardImpl { // {T}: Draw a card, then discard a card. Activate this ability only if you've cast a noncreature spell this turn. this.addAbility(new ActivateIfConditionActivatedAbility( - new DrawDiscardControllerEffect(), new TapSourceCost(), SeekerOfInsightCondition.instance - )); + new DrawDiscardControllerEffect(), new TapSourceCost(), CastNoncreatureSpellThisTurnCondition.instance + ).addHint(CastNoncreatureSpellThisTurnCondition.getHint())); } private SeekerOfInsight(final SeekerOfInsight card) { @@ -43,22 +40,3 @@ public final class SeekerOfInsight extends CardImpl { return new SeekerOfInsight(this); } } - -enum SeekerOfInsightCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - return game - .getState() - .getWatcher(SpellsCastWatcher.class) - .getSpellsCastThisTurn(source.getControllerId()) - .stream() - .anyMatch(spell -> !spell.isCreature(game)); - } - - @Override - public String toString() { - return "you've cast a noncreature spell this turn"; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SwordCoastSerpent.java b/Mage.Sets/src/mage/cards/s/SwordCoastSerpent.java index 1a12aa1277a..5abbfe7fad8 100644 --- a/Mage.Sets/src/mage/cards/s/SwordCoastSerpent.java +++ b/Mage.Sets/src/mage/cards/s/SwordCoastSerpent.java @@ -1,9 +1,8 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CastNoncreatureSpellThisTurnCondition; import mage.abilities.decorator.ConditionalRestrictionEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; @@ -11,13 +10,8 @@ import mage.cards.AdventureCard; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.Game; -import mage.game.stack.Spell; import mage.target.common.TargetCreaturePermanent; -import mage.watchers.common.SpellsCastWatcher; -import java.util.List; -import java.util.Objects; import java.util.UUID; /** @@ -35,9 +29,9 @@ public final class SwordCoastSerpent extends AdventureCard { // Sword Coast Serpent can't be blocked as long as you've cast a noncreature spell this turn. this.addAbility(new SimpleStaticAbility(new ConditionalRestrictionEffect( - new CantBeBlockedSourceEffect(), SwordCoastSerpentCondition.instance, + new CantBeBlockedSourceEffect(), CastNoncreatureSpellThisTurnCondition.instance, "{this} can't be blocked as long as you've cast a noncreature spell this turn" - ))); + )).addHint(CastNoncreatureSpellThisTurnCondition.getHint())); // Capsizing Wave // Return target creature to its owner's hand. @@ -56,20 +50,3 @@ public final class SwordCoastSerpent extends AdventureCard { return new SwordCoastSerpent(this); } } - -enum SwordCoastSerpentCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); - if (watcher == null) { - return false; - } - List spells = watcher.getSpellsCastThisTurn(source.getControllerId()); - return spells != null && spells - .stream() - .filter(Objects::nonNull) - .anyMatch(spell -> !spell.isCreature(game)); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TapestryOfTheAges.java b/Mage.Sets/src/mage/cards/t/TapestryOfTheAges.java index da974f65989..b3aea14c7bb 100644 --- a/Mage.Sets/src/mage/cards/t/TapestryOfTheAges.java +++ b/Mage.Sets/src/mage/cards/t/TapestryOfTheAges.java @@ -2,21 +2,14 @@ package mage.cards.t; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CastNoncreatureSpellThisTurnCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.WatcherScope; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.stack.Spell; -import mage.watchers.Watcher; -import java.util.HashSet; -import java.util.Set; import java.util.UUID; /** @@ -30,10 +23,10 @@ public final class TapestryOfTheAges extends CardImpl { // {2}, {T}: Draw a card. Activate this ability only if you've cast a noncreature spell this turn. Ability ability = new ActivateIfConditionActivatedAbility( new DrawCardSourceControllerEffect(1), - new GenericManaCost(2), PlayerCastNonCreatureSpellCondition.instance + new GenericManaCost(2), CastNoncreatureSpellThisTurnCondition.instance ); ability.addCost(new TapSourceCost()); - this.addAbility(ability, new PlayerCastNonCreatureSpellWatcher()); + this.addAbility(ability.addHint(CastNoncreatureSpellThisTurnCondition.getHint())); } private TapestryOfTheAges(final TapestryOfTheAges card) { @@ -45,47 +38,3 @@ public final class TapestryOfTheAges extends CardImpl { return new TapestryOfTheAges(this); } } - -enum PlayerCastNonCreatureSpellCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - PlayerCastNonCreatureSpellWatcher watcher = game.getState().getWatcher(PlayerCastNonCreatureSpellWatcher.class); - return watcher != null && watcher.playerDidCastNonCreatureSpellThisTurn(source.getControllerId()); - } - - @Override - public String toString() { - return "you've cast a noncreature spell this turn"; - } -} - -class PlayerCastNonCreatureSpellWatcher extends Watcher { - - private Set playerIds = new HashSet<>(); - - public PlayerCastNonCreatureSpellWatcher() { - super(WatcherScope.GAME); - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.SPELL_CAST) { - Spell spell = (Spell) game.getObject(event.getTargetId()); - if (!spell.isCreature(game)) { - playerIds.add(spell.getControllerId()); - } - } - } - - @Override - public void reset() { - super.reset(); - playerIds.clear(); - } - - public boolean playerDidCastNonCreatureSpellThisTurn(UUID playerId) { - return playerIds.contains(playerId); - } -} diff --git a/Mage.Sets/src/mage/sets/MarvelSuperHeroesCommander.java b/Mage.Sets/src/mage/sets/MarvelSuperHeroesCommander.java index 1735e0605d4..ae541df3b91 100644 --- a/Mage.Sets/src/mage/sets/MarvelSuperHeroesCommander.java +++ b/Mage.Sets/src/mage/sets/MarvelSuperHeroesCommander.java @@ -1,6 +1,7 @@ package mage.sets; import mage.cards.ExpansionSet; +import mage.constants.Rarity; import mage.constants.SetType; /** @@ -18,5 +19,7 @@ public final class MarvelSuperHeroesCommander extends ExpansionSet { super("Marvel Super Heroes Commander", "MSC", ExpansionSet.buildDate(2026, 6, 26), SetType.SUPPLEMENTAL); this.blockName = "Marvel Super Heroes"; // for sorting in GUI this.hasBasicLands = false; // temporary + + cards.add(new SetCardInfo("Mister Fantastic", 2, Rarity.MYTHIC, mage.cards.m.MisterFantastic.class)); } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/CastNoncreatureSpellThisTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/CastNoncreatureSpellThisTurnCondition.java new file mode 100644 index 00000000000..6a71b11474c --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/CastNoncreatureSpellThisTurnCondition.java @@ -0,0 +1,35 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.game.Game; +import mage.watchers.common.SpellsCastWatcher; + +/** + * @author TheElk801 + */ +public enum CastNoncreatureSpellThisTurnCondition implements Condition { + instance; + private static final Hint hint = new ConditionHint(instance); + + public static Hint getHint() { + return hint; + } + + @Override + public boolean apply(Game game, Ability source) { + return game + .getState() + .getWatcher(SpellsCastWatcher.class) + .getSpellsCastThisTurn(source.getControllerId()) + .stream() + .anyMatch(spell -> !spell.isCreature(game)); + } + + @Override + public String toString() { + return "you've cast a noncreature spell this turn"; + } +}