[MSC] Implement Mister Fantastic

This commit is contained in:
theelk801 2025-12-09 17:20:19 -05:00
parent ff4470e681
commit b50b14ba96
6 changed files with 134 additions and 105 deletions

View file

@ -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<StackObject> {
instance;
@Override
public boolean apply(StackObject input, Game game) {
return input instanceof Ability && ((Ability) input).isTriggeredAbility();
}
}

View file

@ -1,17 +1,14 @@
package mage.cards.s; package mage.cards.s;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.ActivateIfConditionActivatedAbility; 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.common.TapSourceCost;
import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.effects.common.DrawDiscardControllerEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.game.Game;
import mage.watchers.common.SpellsCastWatcher;
import java.util.UUID; 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. // {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( this.addAbility(new ActivateIfConditionActivatedAbility(
new DrawDiscardControllerEffect(), new TapSourceCost(), SeekerOfInsightCondition.instance new DrawDiscardControllerEffect(), new TapSourceCost(), CastNoncreatureSpellThisTurnCondition.instance
)); ).addHint(CastNoncreatureSpellThisTurnCondition.getHint()));
} }
private SeekerOfInsight(final SeekerOfInsight card) { private SeekerOfInsight(final SeekerOfInsight card) {
@ -43,22 +40,3 @@ public final class SeekerOfInsight extends CardImpl {
return new SeekerOfInsight(this); 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";
}
}

View file

@ -1,9 +1,8 @@
package mage.cards.s; package mage.cards.s;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition; import mage.abilities.condition.common.CastNoncreatureSpellThisTurnCondition;
import mage.abilities.decorator.ConditionalRestrictionEffect; import mage.abilities.decorator.ConditionalRestrictionEffect;
import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect;
@ -11,13 +10,8 @@ import mage.cards.AdventureCard;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.game.Game;
import mage.game.stack.Spell;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.watchers.common.SpellsCastWatcher;
import java.util.List;
import java.util.Objects;
import java.util.UUID; 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. // Sword Coast Serpent can't be blocked as long as you've cast a noncreature spell this turn.
this.addAbility(new SimpleStaticAbility(new ConditionalRestrictionEffect( 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" "{this} can't be blocked as long as you've cast a noncreature spell this turn"
))); )).addHint(CastNoncreatureSpellThisTurnCondition.getHint()));
// Capsizing Wave // Capsizing Wave
// Return target creature to its owner's hand. // Return target creature to its owner's hand.
@ -56,20 +50,3 @@ public final class SwordCoastSerpent extends AdventureCard {
return new SwordCoastSerpent(this); 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<Spell> spells = watcher.getSpellsCastThisTurn(source.getControllerId());
return spells != null && spells
.stream()
.filter(Objects::nonNull)
.anyMatch(spell -> !spell.isCreature(game));
}
}

View file

@ -2,21 +2,14 @@ package mage.cards.t;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.ActivateIfConditionActivatedAbility; 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.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; 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; 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. // {2}, {T}: Draw a card. Activate this ability only if you've cast a noncreature spell this turn.
Ability ability = new ActivateIfConditionActivatedAbility( Ability ability = new ActivateIfConditionActivatedAbility(
new DrawCardSourceControllerEffect(1), new DrawCardSourceControllerEffect(1),
new GenericManaCost(2), PlayerCastNonCreatureSpellCondition.instance new GenericManaCost(2), CastNoncreatureSpellThisTurnCondition.instance
); );
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
this.addAbility(ability, new PlayerCastNonCreatureSpellWatcher()); this.addAbility(ability.addHint(CastNoncreatureSpellThisTurnCondition.getHint()));
} }
private TapestryOfTheAges(final TapestryOfTheAges card) { private TapestryOfTheAges(final TapestryOfTheAges card) {
@ -45,47 +38,3 @@ public final class TapestryOfTheAges extends CardImpl {
return new TapestryOfTheAges(this); 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<UUID> 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);
}
}

View file

@ -1,6 +1,7 @@
package mage.sets; package mage.sets;
import mage.cards.ExpansionSet; import mage.cards.ExpansionSet;
import mage.constants.Rarity;
import mage.constants.SetType; 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); super("Marvel Super Heroes Commander", "MSC", ExpansionSet.buildDate(2026, 6, 26), SetType.SUPPLEMENTAL);
this.blockName = "Marvel Super Heroes"; // for sorting in GUI this.blockName = "Marvel Super Heroes"; // for sorting in GUI
this.hasBasicLands = false; // temporary this.hasBasicLands = false; // temporary
cards.add(new SetCardInfo("Mister Fantastic", 2, Rarity.MYTHIC, mage.cards.m.MisterFantastic.class));
} }
} }

View file

@ -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";
}
}