Fix 'M' cards with card name instead of {this}, fix random test failure in TaigamMasterOpportunistTest

This commit is contained in:
Steven Knipe 2025-07-07 00:46:33 -07:00
parent 57df155a79
commit 3bc22b9f9c
11 changed files with 40 additions and 89 deletions

View file

@ -17,10 +17,9 @@ import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterControlledPermanent;
import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterCreatureCard;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import mage.target.common.TargetControlledPermanent;
import java.util.UUID; import java.util.UUID;
@ -55,7 +54,7 @@ public final class MagusOfTheOrder extends CardImpl {
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addCost(new CompositeCost( ability.addCost(new CompositeCost(
new SacrificeSourceCost(), new SacrificeTargetCost(filter2), new SacrificeSourceCost(), new SacrificeTargetCost(filter2),
"sacrifice Magus of the Order and another green creature" "sacrifice {this} and another green creature"
)); ));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -2,7 +2,6 @@ package mage.cards.m;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.MultipliedValue; import mage.abilities.dynamicvalue.MultipliedValue;
@ -12,6 +11,7 @@ import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect;
import mage.abilities.keyword.*; import mage.abilities.keyword.*;
import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
@ -87,7 +87,7 @@ class MajesticMyriarchEffect extends OneShotEffect {
MajesticMyriarchEffect() { MajesticMyriarchEffect() {
super(Outcome.BoostCreature); super(Outcome.BoostCreature);
this.staticText = "if you control a creature with flying, Majestic Myriarch gains flying until end of turn. " + this.staticText = "if you control a creature with flying, {this} gains flying until end of turn. " +
"The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, reach, trample, and vigilance."; "The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, reach, trample, and vigilance.";
} }

View file

@ -1,7 +1,6 @@
package mage.cards.m; package mage.cards.m;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.ObjectColor; import mage.ObjectColor;
import mage.abilities.Ability; import mage.abilities.Ability;
@ -17,7 +16,6 @@ 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.constants.Zone;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
@ -25,6 +23,8 @@ import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.mageobject.ColorPredicate;
import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInHand;
import java.util.UUID;
/** /**
* *
* @author emerald000 * @author emerald000
@ -49,7 +49,7 @@ public final class MartyrOfAshes extends CardImpl {
// {2}, Reveal X red cards from your hand, Sacrifice Martyr of Ashes: Martyr of Ashes deals X damage to each creature without flying. // {2}, Reveal X red cards from your hand, Sacrifice Martyr of Ashes: Martyr of Ashes deals X damage to each creature without flying.
Effect effect = new DamageAllEffect(RevealTargetFromHandCostCount.instance, filterCreature); Effect effect = new DamageAllEffect(RevealTargetFromHandCostCount.instance, filterCreature);
effect.setText("Martyr of Ashes deals X damage to each creature without flying."); effect.setText("{this} deals X damage to each creature without flying.");
Ability ability = new SimpleActivatedAbility(effect, new GenericManaCost(2)); Ability ability = new SimpleActivatedAbility(effect, new GenericManaCost(2));
ability.addCost(new RevealTargetFromHandCost(new TargetCardInHand(0, Integer.MAX_VALUE, filterHand))); ability.addCost(new RevealTargetFromHandCost(new TargetCardInHand(0, Integer.MAX_VALUE, filterHand)));
ability.addCost(new SacrificeSourceCost()); ability.addCost(new SacrificeSourceCost());

View file

@ -2,10 +2,10 @@ package mage.cards.m;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.common.DiscardCardCost;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.BandingAbility; import mage.abilities.keyword.BandingAbility;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
@ -51,7 +51,7 @@ class MishrasWarMachineEffect extends OneShotEffect {
MishrasWarMachineEffect() { MishrasWarMachineEffect() {
super(Outcome.Sacrifice); super(Outcome.Sacrifice);
staticText = "{this} deals 3 damage to you unless you discard a card. If Mishra's War Machine deals damage to you this way, tap it"; staticText = "{this} deals 3 damage to you unless you discard a card. If {this} deals damage to you this way, tap it";
} }
private MishrasWarMachineEffect(final MishrasWarMachineEffect effect) { private MishrasWarMachineEffect(final MishrasWarMachineEffect effect) {

View file

@ -1,7 +1,6 @@
package mage.cards.m; package mage.cards.m;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
@ -9,14 +8,15 @@ import mage.abilities.effects.common.combat.CantAttackIfDefenderControlsPermanen
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.ComparisonType; import mage.constants.ComparisonType;
import mage.constants.Zone; import mage.constants.SubType;
import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.PowerPredicate; import mage.filter.predicate.mageobject.PowerPredicate;
import mage.filter.predicate.permanent.TappedPredicate; import mage.filter.predicate.permanent.TappedPredicate;
import java.util.UUID;
/** /**
* @author BursegSardaukar * @author BursegSardaukar
*/ */
@ -36,7 +36,7 @@ public final class MoggJailer extends CardImpl {
// Mogg Jailer can't attack if defending player controls an untapped creature with power 2 or less. // Mogg Jailer can't attack if defending player controls an untapped creature with power 2 or less.
Effect effect = new CantAttackIfDefenderControlsPermanent(filter); Effect effect = new CantAttackIfDefenderControlsPermanent(filter);
effect.setText("Mogg Jailer can't attack if defending player controls an untapped creature with power 2 or less."); effect.setText("{this} can't attack if defending player controls an untapped creature with power 2 or less.");
this.addAbility(new SimpleStaticAbility(effect)); this.addAbility(new SimpleStaticAbility(effect));
} }

View file

@ -45,7 +45,7 @@ class MoltenRainEffect extends OneShotEffect {
MoltenRainEffect() { MoltenRainEffect() {
super(Outcome.Damage); super(Outcome.Damage);
this.staticText = "If that land was nonbasic, Molten Rain deals 2 damage to the land's controller"; this.staticText = "If that land was nonbasic, {this} deals 2 damage to the land's controller";
} }
private MoltenRainEffect(final MoltenRainEffect effect) { private MoltenRainEffect(final MoltenRainEffect effect) {

View file

@ -45,7 +45,7 @@ class MorgueBurstEffect extends OneShotEffect {
MorgueBurstEffect() { MorgueBurstEffect() {
super(Outcome.ReturnToHand); super(Outcome.ReturnToHand);
this.staticText = "Return target creature card from your graveyard to your hand. Morgue Burst deals damage to any target equal to the power of the card returned this way"; this.staticText = "Return target creature card from your graveyard to your hand. {this} deals damage to any target equal to the power of the card returned this way";
} }
private MorgueBurstEffect(final MorgueBurstEffect effect) { private MorgueBurstEffect(final MorgueBurstEffect effect) {

View file

@ -1,24 +1,25 @@
package mage.cards.m; package mage.cards.m;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.TopLibraryCardTypeCondition; import mage.abilities.condition.common.TopLibraryCardTypeCondition;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.mana.AddManaOfAnyColorEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.effects.common.continuous.PlayWithTheTopCardRevealedEffect; import mage.abilities.effects.common.continuous.PlayWithTheTopCardRevealedEffect;
import mage.abilities.effects.mana.AddManaOfAnyColorEffect;
import mage.abilities.mana.SimpleManaAbility; import mage.abilities.mana.SimpleManaAbility;
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.Duration; import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone; import mage.constants.Zone;
import java.util.UUID;
/** /**
* *
* @author jeffwadsworth * @author jeffwadsworth
@ -48,7 +49,7 @@ public final class MulDayaChannelers extends CardImpl {
SimpleManaAbility manaAbility = new SimpleManaAbility(Zone.BATTLEFIELD, new AddManaOfAnyColorEffect(2), new TapSourceCost()); SimpleManaAbility manaAbility = new SimpleManaAbility(Zone.BATTLEFIELD, new AddManaOfAnyColorEffect(2), new TapSourceCost());
effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(manaAbility, Duration.WhileOnBattlefield), effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(manaAbility, Duration.WhileOnBattlefield),
new TopLibraryCardTypeCondition(CardType.LAND), new TopLibraryCardTypeCondition(CardType.LAND),
"As long as the top card of your library is a land card, Mul Daya Channelers has \"{T}: Add two mana of any one color.\""); "As long as the top card of your library is a land card, {this} has \"{T}: Add two mana of any one color.\"");
this.addAbility(new SimpleStaticAbility(effect)); this.addAbility(new SimpleStaticAbility(effect));
} }

View file

@ -45,7 +45,7 @@ public final class MuseVessel extends CardImpl {
// {1}: Choose a card exiled with Muse Vessel. You may play that card this turn. // {1}: Choose a card exiled with Muse Vessel. You may play that card this turn.
SimpleActivatedAbility playAbility = new SimpleActivatedAbility(new OneShotNonTargetEffect( SimpleActivatedAbility playAbility = new SimpleActivatedAbility(new OneShotNonTargetEffect(
new AddContinuousEffectToGame(new PlayFromNotOwnHandZoneTargetEffect(Zone.EXILED, Duration.EndOfTurn)) new AddContinuousEffectToGame(new PlayFromNotOwnHandZoneTargetEffect(Zone.EXILED, Duration.EndOfTurn))
.setText("Choose a card exiled with Muse Vessel. You may play that card this turn."), .setText("Choose a card exiled with {this}. You may play that card this turn."),
new TargetCardInExile(StaticFilters.FILTER_CARD), MuseVesselAdjuster.instance new TargetCardInExile(StaticFilters.FILTER_CARD), MuseVesselAdjuster.instance
), new ManaCostsImpl<>("{1}")); ), new ManaCostsImpl<>("{1}"));
this.addAbility(playAbility); this.addAbility(playAbility);

View file

@ -1,39 +1,41 @@
package mage.cards.m; package mage.cards.m;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.MageObject; import mage.abilities.common.DiesThisOrAnotherTriggeredAbility;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.GainLifeEffect;
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.ComparisonType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone; import mage.filter.FilterPermanent;
import mage.game.Game; import mage.filter.common.FilterControlledCreaturePermanent;
import mage.game.events.GameEvent; import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.game.events.GameEvent.EventType; import mage.filter.predicate.mageobject.PowerPredicate;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent; import java.util.UUID;
/** /**
*
* @author jeffwadsworth * @author jeffwadsworth
*/ */
public final class MycoidShepherd extends CardImpl { public final class MycoidShepherd extends CardImpl {
private static final FilterPermanent filter = new FilterControlledCreaturePermanent("another creature you control with power 5 or greater");
static {
filter.add(AnotherPredicate.instance);
filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 4));
}
public MycoidShepherd(UUID ownerId, CardSetInfo setInfo) { public MycoidShepherd(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{G}{W}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{G}{W}");
this.subtype.add(SubType.FUNGUS); this.subtype.add(SubType.FUNGUS);
this.power = new MageInt(5); this.power = new MageInt(5);
this.toughness = new MageInt(4); this.toughness = new MageInt(4);
// Whenever Mycoid Shepherd or another creature you control with power 5 or greater dies, you may gain 5 life. // Whenever Mycoid Shepherd or another creature you control with power 5 or greater dies, you may gain 5 life.
this.addAbility(new MycoidShepherdTriggeredAbility()); this.addAbility(new DiesThisOrAnotherTriggeredAbility(new GainLifeEffect(5), true, filter));
} }
@ -46,55 +48,3 @@ public final class MycoidShepherd extends CardImpl {
return new MycoidShepherd(this); return new MycoidShepherd(this);
} }
} }
class MycoidShepherdTriggeredAbility extends TriggeredAbilityImpl {
public MycoidShepherdTriggeredAbility() {
super(Zone.BATTLEFIELD, new GainLifeEffect(5), true);
setLeavesTheBattlefieldTrigger(true);
}
private MycoidShepherdTriggeredAbility(final MycoidShepherdTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
MageObject lastKnown = game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD);
if (lastKnown == null) {
return false;
}
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
Permanent permanent = zEvent.getTarget();
if (permanent == null) {
return false;
}
if (super.getSourceId().equals(event.getTargetId())
|| permanent.getPower().getValue() > 4
&& permanent.isControlledBy(controllerId)) {
Zone after = game.getState().getZone(event.getTargetId());
return after != null && Zone.GRAVEYARD.match(after);
}
return false;
}
@Override
public String getRule() {
return "Whenever Mycoid Shepherd or another creature you control with power 5 or greater dies, you may gain 5 life.";
}
@Override
public MycoidShepherdTriggeredAbility copy() {
return new MycoidShepherdTriggeredAbility(this);
}
@Override
public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) {
return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game);
}
}

View file

@ -20,6 +20,7 @@ public class TaigamMasterOpportunistTest extends CardTestPlayerBase {
setStrictChooseMode(true); setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, TAIGAM); addCard(Zone.BATTLEFIELD, playerA, TAIGAM);
addCard(Zone.BATTLEFIELD, playerA, "Yawgmoth's Bargain"); // Can shuffle to the top of the library, prevent drawing it
addCard(Zone.HAND, playerA, ORNITHOPTER); addCard(Zone.HAND, playerA, ORNITHOPTER);
addCard(Zone.HAND, playerA, TWINMAW); addCard(Zone.HAND, playerA, TWINMAW);
addCard(Zone.BATTLEFIELD, playerA, "Plateau", 6); addCard(Zone.BATTLEFIELD, playerA, "Plateau", 6);