diff --git a/Mage.Sets/src/mage/cards/a/ArdynTheUsurper.java b/Mage.Sets/src/mage/cards/a/ArdynTheUsurper.java index e0f20d5da57..f2b2dc4ed4a 100644 --- a/Mage.Sets/src/mage/cards/a/ArdynTheUsurper.java +++ b/Mage.Sets/src/mage/cards/a/ArdynTheUsurper.java @@ -75,8 +75,8 @@ class ArdynTheUsurperEffect extends OneShotEffect { ArdynTheUsurperEffect() { super(Outcome.Benefit); - staticText = "at the beginning of combat on your turn, exile up to one target creature card from a graveyard. " + - "If you exiled a card this way, create a token that's a copy of that card, except it's a 5/5 black Demon"; + staticText = "exile up to one target creature card from a graveyard. If you exiled a card this way, " + + "create a token that's a copy of that card, except it's a 5/5 black Demon"; } private ArdynTheUsurperEffect(final ArdynTheUsurperEffect effect) { diff --git a/Mage.Sets/src/mage/cards/b/BarretWallace.java b/Mage.Sets/src/mage/cards/b/BarretWallace.java index 6f5c711394a..e040ec94df4 100644 --- a/Mage.Sets/src/mage/cards/b/BarretWallace.java +++ b/Mage.Sets/src/mage/cards/b/BarretWallace.java @@ -49,7 +49,8 @@ public final class BarretWallace extends CardImpl { // Whenever Barret Wallace attacks, it deals damage equal to the number of equipped creatures you control to defending player. this.addAbility(new AttacksTriggeredAbility( - new DamageTargetEffect(xValue, true, "it", true), + new DamageTargetEffect(xValue, true, "it", true) + .setText("it deals damage equal to the number of equipped creatures you control to defending player"), false, null, SetTargetPointer.PLAYER ).withRuleTextReplacement(true).addHint(hint)); } diff --git a/Mage.Sets/src/mage/cards/b/BlazingBomb.java b/Mage.Sets/src/mage/cards/b/BlazingBomb.java index fbd0d801467..65d58c177fe 100644 --- a/Mage.Sets/src/mage/cards/b/BlazingBomb.java +++ b/Mage.Sets/src/mage/cards/b/BlazingBomb.java @@ -39,7 +39,9 @@ public final class BlazingBomb extends CardImpl { // Blow Up -- {T}, Sacrifice this creature: It deals damage equal to its power to target creature. Activate only as a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility( - new DamageTargetEffect(SourcePermanentPowerValue.NOT_NEGATIVE, "it"), new TapSourceCost() + new DamageTargetEffect(SourcePermanentPowerValue.NOT_NEGATIVE) + .setText("it deals damage equal to its power to target creature"), + new TapSourceCost() ); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/b/BusterSword.java b/Mage.Sets/src/mage/cards/b/BusterSword.java index e8b929dea56..6dea433cb0b 100644 --- a/Mage.Sets/src/mage/cards/b/BusterSword.java +++ b/Mage.Sets/src/mage/cards/b/BusterSword.java @@ -1,10 +1,10 @@ package mage.cards.b; import mage.abilities.Ability; -import mage.abilities.common.DealsCombatDamageEquippedTriggeredAbility; +import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DrawCardTargetEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.keyword.EquipAbility; import mage.cards.CardImpl; @@ -36,7 +36,9 @@ public final class BusterSword extends CardImpl { this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(3, 2))); // Whenever equipped creature deals combat damage to a player, draw a card, then you may cast a spell from your hand with mana value less than or equal to that damage without paying its mana cost. - Ability ability = new DealsCombatDamageEquippedTriggeredAbility(new DrawCardTargetEffect(1)); + Ability ability = new DealsDamageToAPlayerAttachedTriggeredAbility( + new DrawCardSourceControllerEffect(1), "equipped", false + ); ability.addEffect(new BusterSwordEffect()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/c/ChocoSeekerOfParadise.java b/Mage.Sets/src/mage/cards/c/ChocoSeekerOfParadise.java index 1f57195cc1d..0b2c22e85c8 100644 --- a/Mage.Sets/src/mage/cards/c/ChocoSeekerOfParadise.java +++ b/Mage.Sets/src/mage/cards/c/ChocoSeekerOfParadise.java @@ -38,7 +38,9 @@ public final class ChocoSeekerOfParadise extends CardImpl { this.toughness = new MageInt(5); // Whenever one or more Birds you control attack, look at that many cards from the top of your library. You may put one of them into your hand. Then put any number of land cards from among them onto the battlefield tapped and the rest into your graveyard. - this.addAbility(new AttacksWithCreaturesTriggeredAbility(new ChocoSeekerOfParadiseEffect(), 1, filter)); + this.addAbility(new AttacksWithCreaturesTriggeredAbility( + new ChocoSeekerOfParadiseEffect(), 1, filter + ).setTriggerPhrase("Whenever one or more Birds you control attack, ")); // Landfall -- Whenever a land you control enters, Choco gets +1/+0 until end of turn. this.addAbility(new LandfallAbility(new BoostSourceEffect(1, 0, Duration.EndOfTurn))); diff --git a/Mage.Sets/src/mage/cards/c/CliveIfritsDominant.java b/Mage.Sets/src/mage/cards/c/CliveIfritsDominant.java index 4555ed7dee1..8a18243df9c 100644 --- a/Mage.Sets/src/mage/cards/c/CliveIfritsDominant.java +++ b/Mage.Sets/src/mage/cards/c/CliveIfritsDominant.java @@ -38,7 +38,8 @@ public final class CliveIfritsDominant extends CardImpl { // When Clive enters, you may discard your hand, then draw cards equal to your devotion to red. Ability ability = new EntersBattlefieldTriggeredAbility(new DiscardHandControllerEffect(), true); - ability.addEffect(new DrawCardSourceControllerEffect(DevotionCount.R).concatBy(", then")); + ability.addEffect(new DrawCardSourceControllerEffect(DevotionCount.R) + .setText(", then draw cards equal to your devotion to red")); this.addAbility(ability.addHint(DevotionCount.R.getHint())); // {4}{R}{R}, {T}: Exile Clive, then return it to the battlefield transformed under its owner's control. Activate only as a sorcery. diff --git a/Mage.Sets/src/mage/cards/c/CrystallizedSerah.java b/Mage.Sets/src/mage/cards/c/CrystallizedSerah.java index aa2e88a4097..a10acd8f683 100644 --- a/Mage.Sets/src/mage/cards/c/CrystallizedSerah.java +++ b/Mage.Sets/src/mage/cards/c/CrystallizedSerah.java @@ -30,7 +30,7 @@ public final class CrystallizedSerah extends CardImpl { // Legendary creatures you control get +2/+2. this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( - 2, 2, Duration.WhileControlled, StaticFilters.FILTER_CREATURES_LEGENDARY + 2, 2, Duration.WhileOnBattlefield, StaticFilters.FILTER_CREATURES_LEGENDARY ))); } diff --git a/Mage.Sets/src/mage/cards/e/EvilReawakened.java b/Mage.Sets/src/mage/cards/e/EvilReawakened.java index 745c306a11c..ccda5514808 100644 --- a/Mage.Sets/src/mage/cards/e/EvilReawakened.java +++ b/Mage.Sets/src/mage/cards/e/EvilReawakened.java @@ -19,7 +19,7 @@ public final class EvilReawakened extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); // Return target creature card from your graveyard to the battlefield with two additional +1/+1 counters on it. - this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldWithCounterTargetEffect(true, CounterType.P1P1.createInstance())); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldWithCounterTargetEffect(true, CounterType.P1P1.createInstance(2))); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } diff --git a/Mage.Sets/src/mage/cards/f/FangFearlessLCie.java b/Mage.Sets/src/mage/cards/f/FangFearlessLCie.java index cf71fd538a4..6e1c510e378 100644 --- a/Mage.Sets/src/mage/cards/f/FangFearlessLCie.java +++ b/Mage.Sets/src/mage/cards/f/FangFearlessLCie.java @@ -33,7 +33,9 @@ public final class FangFearlessLCie extends CardImpl { this.meldsToClazz = mage.cards.r.RagnarokDivineDeliverance.class; // Whenever one or more cards leave your graveyard, you draw a card and you lose 1 life. This ability triggers only once each turn. - Ability ability = new CardsLeaveGraveyardTriggeredAbility(new DrawCardSourceControllerEffect(1, true)); + Ability ability = new CardsLeaveGraveyardTriggeredAbility( + new DrawCardSourceControllerEffect(1, true) + ).setTriggersLimitEachTurn(1); ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/f/FireMagic.java b/Mage.Sets/src/mage/cards/f/FireMagic.java index 91bb0da53b4..3ecab5d1e90 100644 --- a/Mage.Sets/src/mage/cards/f/FireMagic.java +++ b/Mage.Sets/src/mage/cards/f/FireMagic.java @@ -24,7 +24,7 @@ public final class FireMagic extends CardImpl { // * Fire -- {0} -- Fire Magic deals 1 damage to each creature. this.getSpellAbility().addEffect(new DamageAllEffect(1, StaticFilters.FILTER_PERMANENT_CREATURE)); - this.getSpellAbility().withFirstModeCost(new GenericManaCost(1)); + this.getSpellAbility().withFirstModeCost(new GenericManaCost(0)); this.getSpellAbility().withFirstModeFlavorWord("Fire"); // * Fira -- {2} -- Fire Magic deals 2 damage to each creature. diff --git a/Mage.Sets/src/mage/cards/h/HadesSorcererOfEld.java b/Mage.Sets/src/mage/cards/h/HadesSorcererOfEld.java index 46935cb71a0..270bb430e07 100644 --- a/Mage.Sets/src/mage/cards/h/HadesSorcererOfEld.java +++ b/Mage.Sets/src/mage/cards/h/HadesSorcererOfEld.java @@ -1,16 +1,19 @@ package mage.cards.h; -import java.util.UUID; import mage.MageInt; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.abilities.keyword.VigilanceAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.decorator.ConditionalAsThoughEffect; import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect; import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; +import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; + +import java.util.UUID; /** * @author balazskristof @@ -19,7 +22,7 @@ public final class HadesSorcererOfEld extends CardImpl { public HadesSorcererOfEld(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - + this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.AVATAR); this.power = new MageInt(6); @@ -33,7 +36,9 @@ public final class HadesSorcererOfEld extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // Echo of the Lost -- During your turn you may play cards from your graveyard. - this.addAbility(new SimpleStaticAbility(PlayFromGraveyardControllerEffect.playCards()).withFlavorWord("Echo of the Lost")); + this.addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect( + PlayFromGraveyardControllerEffect.playCards(), MyTurnCondition.instance + ).setText("during your turn, you may play cards from your graveyard")).withFlavorWord("Echo of the Lost")); // If a card or token would be put into your graveyard from anywhere, exile it instead. this.addAbility(new SimpleStaticAbility(new GraveyardFromAnywhereExileReplacementEffect(true, true))); diff --git a/Mage.Sets/src/mage/cards/i/IceMagic.java b/Mage.Sets/src/mage/cards/i/IceMagic.java index 95850e347cc..ab9d2bee0fa 100644 --- a/Mage.Sets/src/mage/cards/i/IceMagic.java +++ b/Mage.Sets/src/mage/cards/i/IceMagic.java @@ -28,7 +28,7 @@ public final class IceMagic extends CardImpl { // * Blizzard -- {0} -- Return target creature to its owner's hand. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().withFirstModeCost(new GenericManaCost(2)); + this.getSpellAbility().withFirstModeCost(new GenericManaCost(0)); this.getSpellAbility().withFirstModeFlavorWord("Blizzard"); // * Blizzara -- {2} -- Target creature's owner puts it on their choice of the top or bottom of their library. diff --git a/Mage.Sets/src/mage/cards/i/IfritWardenOfInferno.java b/Mage.Sets/src/mage/cards/i/IfritWardenOfInferno.java index f1de8a189dd..25f9b3ccc9f 100644 --- a/Mage.Sets/src/mage/cards/i/IfritWardenOfInferno.java +++ b/Mage.Sets/src/mage/cards/i/IfritWardenOfInferno.java @@ -50,10 +50,11 @@ public final class IfritWardenOfInferno extends CardImpl { // II, III -- Brimstone -- Add {R}{R}{R}{R}. If Ifrit has three or more lore counters on it, exile it, then return it to the battlefield sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_III, ability -> { - ability.addEffect(new BasicManaEffect(Mana.RedMana(5))); + ability.addEffect(new BasicManaEffect(Mana.RedMana(4))); ability.addEffect(new ConditionalOneShotEffect( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD), condition, - "If {this} has three or more lore counters on it, exile it, then return it to the battlefield" + "If {this} has three or more lore counters on it, exile it, " + + "then return it to the battlefield (front face up.)." )); ability.withFlavorWord("Brimstone"); }); diff --git a/Mage.Sets/src/mage/cards/k/KainTraitorousDragoon.java b/Mage.Sets/src/mage/cards/k/KainTraitorousDragoon.java index e11d5e5f309..ab4cb5cd4d5 100644 --- a/Mage.Sets/src/mage/cards/k/KainTraitorousDragoon.java +++ b/Mage.Sets/src/mage/cards/k/KainTraitorousDragoon.java @@ -63,7 +63,7 @@ class KainTraitorousDragoonEffect extends OneShotEffect { KainTraitorousDragoonEffect() { super(Outcome.Benefit); - staticText = ", that player gains control of {this}. If they do, you draw that many cards, " + + staticText = "that player gains control of {this}. If they do, you draw that many cards, " + "create that many tapped Treasure tokens, then lose that much life"; } diff --git a/Mage.Sets/src/mage/cards/m/MachinistsArsenal.java b/Mage.Sets/src/mage/cards/m/MachinistsArsenal.java index 56df78e2728..e730429dd30 100644 --- a/Mage.Sets/src/mage/cards/m/MachinistsArsenal.java +++ b/Mage.Sets/src/mage/cards/m/MachinistsArsenal.java @@ -38,7 +38,7 @@ public final class MachinistsArsenal extends CardImpl { .setText("equipped creature gets +2/+2 for each artifact you control")); ability.addEffect(new AddCardSubtypeAttachedEffect( SubType.ARTIFICER, AttachmentType.EQUIPMENT - ).setText(", and is a Artificer in addition to its other types")); + ).setText("and is an Artificer in addition to its other types")); this.addAbility(ability.addHint(ArtifactYouControlHint.instance)); // Machina -- Equip {4} diff --git a/Mage.Sets/src/mage/cards/m/MonksFist.java b/Mage.Sets/src/mage/cards/m/MonksFist.java index 2df1dd242f2..6ca0bd1e6d3 100644 --- a/Mage.Sets/src/mage/cards/m/MonksFist.java +++ b/Mage.Sets/src/mage/cards/m/MonksFist.java @@ -32,6 +32,7 @@ public final class MonksFist extends CardImpl { ability.addEffect(new AddCardSubtypeAttachedEffect( SubType.MONK, AttachmentType.EQUIPMENT ).setText("and is a Monk in addition to its other types")); + this.addAbility(ability); // Equip {2} this.addAbility(new EquipAbility(2)); diff --git a/Mage.Sets/src/mage/cards/n/NetheresePuzzleWard.java b/Mage.Sets/src/mage/cards/n/NetheresePuzzleWard.java index d9fc5f5756d..350c48aadf3 100644 --- a/Mage.Sets/src/mage/cards/n/NetheresePuzzleWard.java +++ b/Mage.Sets/src/mage/cards/n/NetheresePuzzleWard.java @@ -2,10 +2,10 @@ package mage.cards.n; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.keyword.ScryEffect; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -15,7 +15,6 @@ import mage.game.Game; import mage.game.events.DieRolledEvent; import mage.game.events.GameEvent; import mage.players.Player; -import mage.util.CardUtil; import java.util.UUID; @@ -79,6 +78,7 @@ class NetheresePuzzleWardTriggeredAbility extends TriggeredAbilityImpl { NetheresePuzzleWardTriggeredAbility() { super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1)); this.withFlavorWord("Perfect Illumination"); + this.setTriggerPhrase("Whenever you roll a die's highest natural result, "); } private NetheresePuzzleWardTriggeredAbility(final NetheresePuzzleWardTriggeredAbility ability) { @@ -101,10 +101,4 @@ class NetheresePuzzleWardTriggeredAbility extends TriggeredAbilityImpl { public NetheresePuzzleWardTriggeredAbility copy() { return new NetheresePuzzleWardTriggeredAbility(this); } - - @Override - public String getRule() { - return CardUtil.italicizeWithEmDash(flavorWord) - + "Whenever you roll a die's highest natural result, draw a card."; - } } diff --git a/Mage.Sets/src/mage/cards/o/OmegaHeartlessEvolution.java b/Mage.Sets/src/mage/cards/o/OmegaHeartlessEvolution.java index ee8dc6ccc24..5ace61c5509 100644 --- a/Mage.Sets/src/mage/cards/o/OmegaHeartlessEvolution.java +++ b/Mage.Sets/src/mage/cards/o/OmegaHeartlessEvolution.java @@ -52,7 +52,7 @@ public final class OmegaHeartlessEvolution extends CardImpl { ability.addEffect(new AddCountersTargetEffect(CounterType.STUN.createInstance(), xValue) .setTargetPointer(new EachTargetPointer()) .setText("Put X stun counters on each of those permanents")); - ability.addEffect(new GainLifeEffect(xValue).concatBy("and")); + ability.addEffect(new GainLifeEffect(xValue).setText("and you gain X life, where X is the number of nonbasic lands you control")); ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_PERMANENT_NON_LAND)); this.addAbility(ability.withFlavorWord("Wave Cannon").setTargetAdjuster(new ForEachOpponentTargetsAdjuster())); } diff --git a/Mage.Sets/src/mage/cards/p/ProsperTomeBound.java b/Mage.Sets/src/mage/cards/p/ProsperTomeBound.java index 6d47b03d9fc..a616e9ccb69 100644 --- a/Mage.Sets/src/mage/cards/p/ProsperTomeBound.java +++ b/Mage.Sets/src/mage/cards/p/ProsperTomeBound.java @@ -1,11 +1,11 @@ package mage.cards.p; import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.PlayCardTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -57,7 +57,7 @@ class ProsperTomeBoundTriggeredAbility extends PlayCardTriggeredAbility { ProsperTomeBoundTriggeredAbility() { super(TargetController.YOU, Zone.BATTLEFIELD, new CreateTokenEffect(new TreasureToken())); - this.flavorWord = "Pact Boon"; + this.withFlavorWord("Pact Boon"); setTriggerPhrase("Whenever you play a card from exile, "); } diff --git a/Mage.Sets/src/mage/cards/q/QuistisTrepe.java b/Mage.Sets/src/mage/cards/q/QuistisTrepe.java index c3614f37b37..668f1dc4968 100644 --- a/Mage.Sets/src/mage/cards/q/QuistisTrepe.java +++ b/Mage.Sets/src/mage/cards/q/QuistisTrepe.java @@ -36,7 +36,7 @@ public final class QuistisTrepe extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility( new MayCastTargetCardEffect(CastManaAdjustment.AS_THOUGH_ANY_MANA_TYPE, true) ); - this.getSpellAbility().addTarget(new TargetCardInGraveyard(filter)); + ability.addTarget(new TargetCardInGraveyard(filter)); this.addAbility(ability.withFlavorWord("Blue Magic")); } diff --git a/Mage.Sets/src/mage/cards/r/RaubahnBullOfAlaMhigo.java b/Mage.Sets/src/mage/cards/r/RaubahnBullOfAlaMhigo.java index 4635e005ccc..b4710b45bb7 100644 --- a/Mage.Sets/src/mage/cards/r/RaubahnBullOfAlaMhigo.java +++ b/Mage.Sets/src/mage/cards/r/RaubahnBullOfAlaMhigo.java @@ -35,7 +35,7 @@ public final class RaubahnBullOfAlaMhigo extends CardImpl { // Ward--Pay life equal to Raubahn's power. this.addAbility(new WardAbility(new PayLifeCost( - SourcePermanentPowerValue.NOT_NEGATIVE, "Pay life equal to {this}'s power" + SourcePermanentPowerValue.NOT_NEGATIVE, "life equal to {this}'s power" ))); // Whenever Raubahn attacks, attach up to one target Equipment you control to target attacking creature. diff --git a/Mage.Sets/src/mage/cards/r/RenoAndRude.java b/Mage.Sets/src/mage/cards/r/RenoAndRude.java index 1332616b45e..b1fae8b0778 100644 --- a/Mage.Sets/src/mage/cards/r/RenoAndRude.java +++ b/Mage.Sets/src/mage/cards/r/RenoAndRude.java @@ -56,7 +56,7 @@ class RenoAndRudeEffect extends OneShotEffect { RenoAndRudeEffect() { super(Outcome.Benefit); - staticText = ", exile the top card of that player's library. " + + staticText = "exile the top card of that player's library. " + "Then you may sacrifice another creature or artifact. If you do, " + "you may play the exiled card this turn, and mana of any type can be spent to cast it"; } diff --git a/Mage.Sets/src/mage/cards/s/SagesNouliths.java b/Mage.Sets/src/mage/cards/s/SagesNouliths.java index 20b2a425bd9..642afdad19f 100644 --- a/Mage.Sets/src/mage/cards/s/SagesNouliths.java +++ b/Mage.Sets/src/mage/cards/s/SagesNouliths.java @@ -38,7 +38,7 @@ public final class SagesNouliths extends CardImpl { triggeredAbility.addTarget(new TargetAttackingCreature()); ability.addEffect(new GainAbilityAttachedEffect( triggeredAbility, AttachmentType.EQUIPMENT - ).setText("has \"Whenever this creature attacks, untap target attacking creature,\"")); + ).setText(", has \"Whenever this creature attacks, untap target attacking creature,\"")); ability.addEffect(new AddCardSubtypeAttachedEffect( SubType.CLERIC, AttachmentType.EQUIPMENT ).setText("and is a Cleric in addition to its other types")); diff --git a/Mage.Sets/src/mage/cards/s/SazhKatzroy.java b/Mage.Sets/src/mage/cards/s/SazhKatzroy.java index e1af5896abb..471c30bd44e 100644 --- a/Mage.Sets/src/mage/cards/s/SazhKatzroy.java +++ b/Mage.Sets/src/mage/cards/s/SazhKatzroy.java @@ -16,6 +16,7 @@ import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -47,13 +48,14 @@ public final class SazhKatzroy extends CardImpl { // When Sazh Katzroy enters, you may search your library for a Bird or basic land card, reveal it, put it into your hand, then shuffle. this.addAbility(new EntersBattlefieldTriggeredAbility( - new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true) + new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true), true )); // Whenever Sazh Katzroy attacks, put counter on target creature, then double the number of +1/+1 counters on that creature. Ability ability = new AttacksTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); ability.addEffect(new DoubleCountersTargetEffect(CounterType.P1P1) .setText(", then double the number of +1/+1 counters on that creature")); + ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SephirothFabledSOLDIER.java b/Mage.Sets/src/mage/cards/s/SephirothFabledSOLDIER.java index 2ce8c407227..b0e3b72d950 100644 --- a/Mage.Sets/src/mage/cards/s/SephirothFabledSOLDIER.java +++ b/Mage.Sets/src/mage/cards/s/SephirothFabledSOLDIER.java @@ -13,6 +13,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; import mage.filter.StaticFilters; +import mage.target.common.TargetOpponent; import mage.watchers.common.AbilityResolvedWatcher; import java.util.UUID; @@ -47,6 +48,7 @@ public final class SephirothFabledSOLDIER extends CardImpl { ); ability.addEffect(new GainLifeEffect(1).concatBy("and")); ability.addEffect(new IfAbilityHasResolvedXTimesEffect(4, new TransformSourceEffect())); + ability.addTarget(new TargetOpponent()); this.addAbility(ability, new AbilityResolvedWatcher()); } diff --git a/Mage.Sets/src/mage/cards/s/ShantottoTacticianMagician.java b/Mage.Sets/src/mage/cards/s/ShantottoTacticianMagician.java index 1c87eaab586..9b99032bec0 100644 --- a/Mage.Sets/src/mage/cards/s/ShantottoTacticianMagician.java +++ b/Mage.Sets/src/mage/cards/s/ShantottoTacticianMagician.java @@ -47,7 +47,7 @@ public final class ShantottoTacticianMagician extends CardImpl { ability.addEffect(new ConditionalOneShotEffect( new DrawCardSourceControllerEffect(1), ShantottoTacticianMagicianCondition.instance, - "If X is 4 or greater, draw a card" + "If X is 4 or more, draw a card" )); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/StolenUniform.java b/Mage.Sets/src/mage/cards/s/StolenUniform.java index 323e3b4dcf0..7eb0c03ed8a 100644 --- a/Mage.Sets/src/mage/cards/s/StolenUniform.java +++ b/Mage.Sets/src/mage/cards/s/StolenUniform.java @@ -59,8 +59,7 @@ class StolenUniformAttachEffect extends OneShotEffect { StolenUniformAttachEffect() { super(Outcome.Benefit); - staticText = "Attach it to the chosen creature. When you lose control of that Equipment this turn, " + - "if it's attached to a creature you control, unattach it"; + staticText = "Attach it to the chosen creature"; this.setTargetPointer(new EachTargetPointer()); } diff --git a/Mage.Sets/src/mage/cards/s/SummonEsperRamuh.java b/Mage.Sets/src/mage/cards/s/SummonEsperRamuh.java index 35b1615f771..125dda66ac6 100644 --- a/Mage.Sets/src/mage/cards/s/SummonEsperRamuh.java +++ b/Mage.Sets/src/mage/cards/s/SummonEsperRamuh.java @@ -47,7 +47,9 @@ public final class SummonEsperRamuh extends CardImpl { // I -- Judgment Bolt -- This creature deals damage equal to the number of noncreature, nonland cards in your graveyard to target creature an opponent controls. sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, ability -> { - ability.addEffect(new DamageTargetEffect(xValue)); + ability.addEffect(new DamageTargetEffect(xValue) + .setText("{this} deals damage equal to the number of noncreature, nonland " + + "cards in your graveyard to target creature an opponent controls")); ability.addTarget(new TargetOpponentsCreaturePermanent()); ability.withFlavorWord("Judgment Bolt"); }); diff --git a/Mage.Sets/src/mage/cards/s/SummonFenrir.java b/Mage.Sets/src/mage/cards/s/SummonFenrir.java index 14f09cb5fd2..3f064954b5a 100644 --- a/Mage.Sets/src/mage/cards/s/SummonFenrir.java +++ b/Mage.Sets/src/mage/cards/s/SummonFenrir.java @@ -44,7 +44,7 @@ public final class SummonFenrir extends CardImpl { // I -- Crescent Fang -- Search your library for a basic land card, put it onto the battlefield tapped, then shuffle. sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, ability -> { ability.addEffect(new SearchLibraryPutInPlayEffect( - new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true, true + new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true )); ability.withFlavorWord("Crescent Fang"); }); diff --git a/Mage.Sets/src/mage/cards/s/SummonKnightsOfRound.java b/Mage.Sets/src/mage/cards/s/SummonKnightsOfRound.java index 9b3a4e17b34..ce5289506a0 100644 --- a/Mage.Sets/src/mage/cards/s/SummonKnightsOfRound.java +++ b/Mage.Sets/src/mage/cards/s/SummonKnightsOfRound.java @@ -35,11 +35,14 @@ public final class SummonKnightsOfRound extends CardImpl { SagaAbility sagaAbility = new SagaAbility(this, SagaChapter.CHAPTER_V); // I, II, III, IV -- Create three 2/2 white Knight creature tokens. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_IV, new CreateTokenEffect(new WaylayToken())); + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_IV, + new CreateTokenEffect(new WaylayToken(), 3) + ); // V -- Ultimate End -- Other creatures you control get +2/+2 until end of turn. Put an indestructible counter on each of them. sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_V, ability -> { - ability.addEffect(new BoostControlledEffect(2, 2, Duration.EndOfTurn)); + ability.addEffect(new BoostControlledEffect(2, 2, Duration.EndOfTurn, true)); ability.addEffect(new AddCountersAllEffect( CounterType.INDESTRUCTIBLE.createInstance(), StaticFilters.FILTER_OTHER_CONTROLLED_CREATURES diff --git a/Mage.Sets/src/mage/cards/s/SummonPrimalOdin.java b/Mage.Sets/src/mage/cards/s/SummonPrimalOdin.java index 4d65029bb48..b095557ffe5 100644 --- a/Mage.Sets/src/mage/cards/s/SummonPrimalOdin.java +++ b/Mage.Sets/src/mage/cards/s/SummonPrimalOdin.java @@ -47,7 +47,7 @@ public final class SummonPrimalOdin extends CardImpl { new DealsCombatDamageToAPlayerTriggeredAbility( new LoseGameTargetPlayerEffect(), false, true ), Duration.Custom - )); + ).setText("{this} gains \"Whenever this creature deals combat damage to a player, that player loses the game.\"")); ability.withFlavorWord("Zantetsuken"); }); diff --git a/Mage.Sets/src/mage/cards/t/TheFireCrystal.java b/Mage.Sets/src/mage/cards/t/TheFireCrystal.java index 960103c607b..b91eca491bc 100644 --- a/Mage.Sets/src/mage/cards/t/TheFireCrystal.java +++ b/Mage.Sets/src/mage/cards/t/TheFireCrystal.java @@ -47,7 +47,7 @@ public final class TheFireCrystal extends CardImpl { // Creatures you control have haste. this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - HasteAbility.getInstance(), Duration.WhileControlled, + HasteAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES ))); diff --git a/Mage.Sets/src/mage/cards/t/TheGoldSaucer.java b/Mage.Sets/src/mage/cards/t/TheGoldSaucer.java index 70b50f64d43..9ccf8468d27 100644 --- a/Mage.Sets/src/mage/cards/t/TheGoldSaucer.java +++ b/Mage.Sets/src/mage/cards/t/TheGoldSaucer.java @@ -14,7 +14,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.game.permanent.token.custom.CreatureToken; +import mage.game.permanent.token.TreasureToken; import java.util.UUID; @@ -33,13 +33,13 @@ public final class TheGoldSaucer extends CardImpl { // {2}, {T}: Flip a coin. If you win the flip, create a Treasure token. Ability ability = new SimpleActivatedAbility( - new FlipCoinEffect(new CreateTokenEffect(new CreatureToken())), new GenericManaCost(2) + new FlipCoinEffect(new CreateTokenEffect(new TreasureToken())), new GenericManaCost(2) ); ability.addCost(new TapSourceCost()); this.addAbility(ability); // {3}, {T}, Sacrifice two artifacts: Draw a card. - ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(2), new GenericManaCost(3)); + ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(3)); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeTargetCost(2, StaticFilters.FILTER_PERMANENT_ARTIFACTS)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/t/TifaLockhart.java b/Mage.Sets/src/mage/cards/t/TifaLockhart.java index 0ef792afaf2..f9be1fc6bdb 100644 --- a/Mage.Sets/src/mage/cards/t/TifaLockhart.java +++ b/Mage.Sets/src/mage/cards/t/TifaLockhart.java @@ -36,7 +36,7 @@ public final class TifaLockhart extends CardImpl { this.addAbility(new LandfallAbility(new BoostSourceEffect( SourcePermanentPowerValue.ALLOW_NEGATIVE, StaticValue.get(0), Duration.EndOfTurn - ).setText(" double {this}'s power until end of turn"))); + ).setText("double {this}'s power until end of turn"))); } private TifaLockhart(final TifaLockhart card) { diff --git a/Mage.Sets/src/mage/cards/t/TravelingChocobo.java b/Mage.Sets/src/mage/cards/t/TravelingChocobo.java index f66dead4ac6..679c1602ac8 100644 --- a/Mage.Sets/src/mage/cards/t/TravelingChocobo.java +++ b/Mage.Sets/src/mage/cards/t/TravelingChocobo.java @@ -66,7 +66,7 @@ class TravelingChocoboEffect extends ReplacementEffectImpl { TravelingChocoboEffect() { super(Duration.WhileOnBattlefield, Outcome.Benefit); - staticText = "if land or Bird entering the battlefield causes a triggered ability " + + staticText = "if a land or Bird you control entering the battlefield causes a triggered ability " + "of a permanent you control to trigger, that ability triggers an additional time"; } @@ -102,6 +102,7 @@ class TravelingChocoboEffect extends ReplacementEffectImpl { EntersTheBattlefieldEvent entersTheBattlefieldEvent = (EntersTheBattlefieldEvent) sourceEvent; return (entersTheBattlefieldEvent.getTarget().isLand(game) || entersTheBattlefieldEvent.getTarget().hasSubtype(SubType.BIRD, game)) + && entersTheBattlefieldEvent.getTarget().isControlledBy(source.getControllerId()) && game.getPermanent(numberOfTriggersEvent.getSourceId()) != null; } diff --git a/Mage.Sets/src/mage/cards/u/UltimaWeapon.java b/Mage.Sets/src/mage/cards/u/UltimaWeapon.java index 380e021f546..5e6da88ac2e 100644 --- a/Mage.Sets/src/mage/cards/u/UltimaWeapon.java +++ b/Mage.Sets/src/mage/cards/u/UltimaWeapon.java @@ -1,7 +1,7 @@ package mage.cards.u; import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.AttacksAttachedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; @@ -27,7 +27,7 @@ public final class UltimaWeapon extends CardImpl { this.subtype.add(SubType.EQUIPMENT); // Whenever equipped creature attacks, destroy target creature an opponent controls. - Ability ability = new AttacksTriggeredAbility(new DestroyTargetEffect()); + Ability ability = new AttacksAttachedTriggeredAbility(new DestroyTargetEffect()); ability.addTarget(new TargetOpponentsCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/w/WarriorsSword.java b/Mage.Sets/src/mage/cards/w/WarriorsSword.java index 02b90a950d2..a0649f7b9c1 100644 --- a/Mage.Sets/src/mage/cards/w/WarriorsSword.java +++ b/Mage.Sets/src/mage/cards/w/WarriorsSword.java @@ -31,7 +31,7 @@ public final class WarriorsSword extends CardImpl { Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(3, 2)); ability.addEffect(new AddCardSubtypeAttachedEffect( SubType.WARRIOR, AttachmentType.EQUIPMENT - ).setText(", and is a Warrior in addition to its other types")); + ).setText("and is a Warrior in addition to its other types")); this.addAbility(ability); // Equip {5} diff --git a/Mage.Sets/src/mage/cards/w/WorldMap.java b/Mage.Sets/src/mage/cards/w/WorldMap.java index 1bc2d325e0c..6272b56cc1f 100644 --- a/Mage.Sets/src/mage/cards/w/WorldMap.java +++ b/Mage.Sets/src/mage/cards/w/WorldMap.java @@ -5,7 +5,7 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -23,7 +23,7 @@ public final class WorldMap extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); // {1}, {T}, Sacrifice this artifact: Search your library for a basic land card, reveal it, put it into your hand, then shuffle. - Ability ability = new SimpleActivatedAbility(new SearchLibraryPutInPlayEffect( + Ability ability = new SimpleActivatedAbility(new SearchLibraryPutInHandEffect( new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true ), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); @@ -31,7 +31,7 @@ public final class WorldMap extends CardImpl { this.addAbility(ability); // {3}, {T}, Sacrifice this artifact: Search your library for a land card, reveal it, put it into your hand, then shuffle. - ability = new SimpleActivatedAbility(new SearchLibraryPutInPlayEffect( + ability = new SimpleActivatedAbility(new SearchLibraryPutInHandEffect( new TargetCardInLibrary(StaticFilters.FILTER_CARD_LAND), true ), new GenericManaCost(3)); ability.addCost(new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/x/XandeDarkMage.java b/Mage.Sets/src/mage/cards/x/XandeDarkMage.java index 8c287e2c752..744825c5662 100644 --- a/Mage.Sets/src/mage/cards/x/XandeDarkMage.java +++ b/Mage.Sets/src/mage/cards/x/XandeDarkMage.java @@ -22,7 +22,7 @@ import java.util.UUID; */ public final class XandeDarkMage extends CardImpl { - private static final FilterCard filter = new FilterCard("noncreature, nonland card in your graveyard"); + private static final FilterCard filter = new FilterCard("noncreature, nonland card"); static { filter.add(Predicates.not(CardType.CREATURE.getPredicate())); diff --git a/Mage.Sets/src/mage/cards/y/YiazmatUltimateMark.java b/Mage.Sets/src/mage/cards/y/YiazmatUltimateMark.java index fc358bd8549..277a6a11108 100644 --- a/Mage.Sets/src/mage/cards/y/YiazmatUltimateMark.java +++ b/Mage.Sets/src/mage/cards/y/YiazmatUltimateMark.java @@ -11,6 +11,7 @@ import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.constants.SuperType; import mage.filter.FilterPermanent; @@ -46,7 +47,7 @@ public final class YiazmatUltimateMark extends CardImpl { // {1}{B}, Sacrifice another creature or artifact: Yiazmat gains indestructible until end of turn. Tap it. Ability ability = new SimpleActivatedAbility( - new GainAbilitySourceEffect(IndestructibleAbility.getInstance()), new ManaCostsImpl<>("{1}{B}") + new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{1}{B}") ); ability.addCost(new SacrificeTargetCost(filter)); ability.addEffect(new TapSourceEffect().setText("tap it")); diff --git a/Mage.Sets/src/mage/cards/y/YshtolaRhul.java b/Mage.Sets/src/mage/cards/y/YshtolaRhul.java index 2083b4ed242..34939081db4 100644 --- a/Mage.Sets/src/mage/cards/y/YshtolaRhul.java +++ b/Mage.Sets/src/mage/cards/y/YshtolaRhul.java @@ -1,21 +1,18 @@ package mage.cards.y; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileThenReturnTargetEffect; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.TurnPhase; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; import mage.game.Game; import mage.game.turn.TurnMod; import mage.target.common.TargetControlledCreaturePermanent; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; + +import java.util.UUID; /** * @author balazskristof @@ -24,7 +21,7 @@ public final class YshtolaRhul extends CardImpl { public YshtolaRhul(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}"); - + this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.CAT); this.subtype.add(SubType.DRUID); @@ -32,9 +29,9 @@ public final class YshtolaRhul extends CardImpl { this.toughness = new MageInt(5); // At the beginning of your end step, exile target creature you control, then return it to the battlefield under its owner's control. Then if it's the first end step of the turn, there is an additional end step after this step. - Ability ability = new BeginningOfEndStepTriggeredAbility(new ExileThenReturnTargetEffect(true, false)); + Ability ability = new BeginningOfEndStepTriggeredAbility(new ExileThenReturnTargetEffect(false, false)); ability.addTarget(new TargetControlledCreaturePermanent()); - ability.addEffect(new YshtolaRhulEffect().concatBy("Then")); + ability.addEffect(new YshtolaRhulEffect()); this.addAbility(ability); } @@ -51,7 +48,7 @@ public final class YshtolaRhul extends CardImpl { class YshtolaRhulEffect extends OneShotEffect { public YshtolaRhulEffect() { super(Outcome.Benefit); - staticText = "if it's the first end step of the turn, there is an additional end step after this step"; + staticText = "Then if it's the first end step of the turn, there is an additional end step after this step"; } protected YshtolaRhulEffect(final YshtolaRhulEffect effect) { @@ -65,10 +62,10 @@ class YshtolaRhulEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - if (game.getTurn().getPhase(TurnPhase.END).getCount() == 0) { - TurnMod end = new TurnMod(game.getState().getActivePlayerId()).withExtraPhase(TurnPhase.END); - game.getState().getTurnMods().add(end); + if (game.getTurn().getPhase(TurnPhase.END).getCount() != 0) { + return false; } + game.getState().getTurnMods().add(new TurnMod(game.getState().getActivePlayerId()).withExtraPhase(TurnPhase.END)); return true; } } diff --git a/Mage.Sets/src/mage/cards/z/ZellDincht.java b/Mage.Sets/src/mage/cards/z/ZellDincht.java index e58ec740387..6fc27784a49 100644 --- a/Mage.Sets/src/mage/cards/z/ZellDincht.java +++ b/Mage.Sets/src/mage/cards/z/ZellDincht.java @@ -45,7 +45,7 @@ public final class ZellDincht extends CardImpl { // At the beginning of your end step, return a land you control to its owner's hand. this.addAbility(new BeginningOfEndStepTriggeredAbility( - new ReturnToHandChosenControlledPermanentEffect(StaticFilters.FILTER_CONTROLLED_PERMANENT_A_LAND) + new ReturnToHandChosenControlledPermanentEffect(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND) )); } diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index a64121303de..864939b06d5 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -32,6 +32,7 @@ import mage.constants.*; import mage.filter.Filter; import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicates; +import mage.game.Game; import mage.game.command.Dungeon; import mage.game.command.Plane; import mage.game.draft.DraftCube; @@ -70,7 +71,7 @@ public class VerifyCardDataTest { private static final Logger logger = Logger.getLogger(VerifyCardDataTest.class); - private static final String FULL_ABILITIES_CHECK_SET_CODES = "WHO"; // check ability text due mtgjson, can use multiple sets like MAT;CMD or * for all + private static final String FULL_ABILITIES_CHECK_SET_CODES = "FIN"; // check ability text due mtgjson, can use multiple sets like MAT;CMD or * for all private static final boolean CHECK_ONLY_ABILITIES_TEXT = false; // use when checking text locally, suppresses unnecessary checks and output messages private static final boolean CHECK_COPYABLE_FIELDS = true; // disable for better verify test performance @@ -2320,7 +2321,81 @@ public class VerifyCardDataTest { // TODO: add legality checks (by sets and cards, by banned) } - private String prepareRule(String cardName, String rule) { + private static final List selfRefNamedSubtypes = Arrays.asList( + SubType.EQUIPMENT, + SubType.VEHICLE, + SubType.AURA, + SubType.CLASS, + SubType.SAGA, + SubType.SIEGE + ); + + private static String applySelfReference(String rule, MageObject mageObject, Game game) { + return rule + .replace("{this}", getCardSelfReference(mageObject, game)) + .replace(". this", ". This") + .replace("\nthis", "\nThis") + .replace("-this", "-This") + .replace(": this", ": This") + .replace("&bull this", "&bull This") + .replace("— this", "— This") + .replace("—this", "—This") + .replace("- this", "- This"); + } + + /** + * Returns the description of the card for rules text that references itself. + * Applies to abilities that function only on the battlefield. + * Does not account for every exception. + * Details here + */ + private static String getCardSelfReference(MageObject mageObject, Game game) { + if (!mageObject.isPermanent(game)) { + return mageObject.getName(); + } + if (mageObject.isPlaneswalker(game)) { + // try to ref by planeswalker name which is subtype + return mageObject + .getSubtype(game) + .stream() + .filter(SubType.getPlaneswalkerTypes()::contains) + .findFirst() + .map(SubType::getDescription) + .orElse(mageObject.getName()); + } + if (mageObject.isLegendary(game)) { + // Generate shortname for legendary permanent (other than planeswalker) + List parts = Arrays.asList(mageObject.getName().split("(, | of the )")); + if (parts.size() > 1) { + return parts.get(0); + } else { + return mageObject.getName(); + } + } + if (mageObject.isCreature(game)) { + return "this creature"; + } + if (mageObject.isLand(game)) { + return "this land"; + } + for (SubType subType : selfRefNamedSubtypes) { + if (mageObject.hasSubtype(subType, game)) { + return "this " + subType.getDescription(); + } + } + if (mageObject.isBattle(game)) { + return "this battle"; + } + if (mageObject.isEnchantment(game)) { + return "this enchantment"; + } + if (mageObject.isArtifact(game)) { + return "this artifact"; + } + return "this permanent"; + } + + private String prepareRule(Card card, String rule) { // remove and optimize rule text for analyze String newRule = rule; @@ -2336,8 +2411,7 @@ public class VerifyCardDataTest { } // replace special text and symbols - newRule = newRule - .replace("{this}", cardName) + newRule = applySelfReference(newRule, card, null) .replace("−", "-") .replace("—", "-") .replace("—", "-"); @@ -2349,7 +2423,7 @@ public class VerifyCardDataTest { newRule = CardNameUtil.normalizeCardName(newRule); - return newRule.trim(); + return CardUtil.getTextWithFirstCharUpperCase(newRule.trim()); } @Test @@ -2582,7 +2656,7 @@ public class VerifyCardDataTest { String[] refRules = refText.split("[\\$\\\n]"); // ref card's abilities can be splited by \n or $ chars for (int i = 0; i < refRules.length; i++) { - refRules[i] = prepareRule(card.getName(), refRules[i]); + refRules[i] = prepareRule(card, refRules[i]); } if (ref.subtypes.contains("Adventure")) { @@ -2615,7 +2689,7 @@ public class VerifyCardDataTest { .replace("", "") .split("[\\$\\\n]"); for (int i = 0; i < cardRules.length; i++) { - cardRules[i] = prepareRule(card.getName(), cardRules[i]); + cardRules[i] = prepareRule(card, cardRules[i]); } boolean isFine = true; diff --git a/Mage/src/main/java/mage/abilities/Ability.java b/Mage/src/main/java/mage/abilities/Ability.java index 93e286a4f56..4621d104feb 100644 --- a/Mage/src/main/java/mage/abilities/Ability.java +++ b/Mage/src/main/java/mage/abilities/Ability.java @@ -474,6 +474,11 @@ public interface Ability extends Controllable, Serializable { */ Ability withFlavorWord(String flavorWord); + /** + * Gets rule prefix for text generation + */ + String addRulePrefix(String rule); + /** * Sets flavor word for first mode */ diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index 84d5ce45c48..cb73a0ec282 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -1018,38 +1018,28 @@ public abstract class AbilityImpl implements Ability { String ruleStart = sbRule.toString(); String text = getModes().getText(); - String rule; + StringBuilder rule = new StringBuilder(); if (!text.isEmpty()) { if (ruleStart.length() > 1) { String end = ruleStart.substring(ruleStart.length() - 2).trim(); if (end.isEmpty() || end.equals(":") || end.equals(".")) { - rule = ruleStart + CardUtil.getTextWithFirstCharUpperCase(text); + rule.append(ruleStart + CardUtil.getTextWithFirstCharUpperCase(text)); } else { - rule = ruleStart + text; + rule.append(ruleStart + text); } } else { - rule = ruleStart + text; + rule.append(ruleStart + text); } } else { - rule = ruleStart; - } - String prefix; - if (this instanceof TriggeredAbility || this instanceof EntersBattlefieldAbility) { - prefix = null; - } else if (abilityWord != null) { - prefix = abilityWord.formatWord(); - } else if (flavorWord != null) { - prefix = CardUtil.italicizeWithEmDash(flavorWord); - } else { - prefix = null; - } - if (prefix != null) { - rule = prefix + CardUtil.getTextWithFirstCharUpperCase(rule); + rule.append(ruleStart); } if (appendToRule != null) { - rule = rule.concat(appendToRule); + rule.append(appendToRule); } - return rule; + if (this instanceof TriggeredAbility || this instanceof EntersBattlefieldAbility) { + return rule.toString(); + } + return addRulePrefix(rule.toString()); } @Override @@ -1479,6 +1469,17 @@ public abstract class AbilityImpl implements Ability { return this; } + @Override + public String addRulePrefix(String rule) { + if (abilityWord != null) { + return abilityWord.formatWord() + CardUtil.getTextWithFirstCharUpperCase(rule); + } else if (flavorWord != null) { + return CardUtil.italicizeWithEmDash(flavorWord) + CardUtil.getTextWithFirstCharUpperCase(rule); + } else { + return rule; + } + } + @Override public Ability withFirstModeFlavorWord(String flavorWord) { this.modes.getMode().withFlavorWord(flavorWord); diff --git a/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java b/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java index 7aa43910eca..93100ce08c3 100644 --- a/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java @@ -294,16 +294,6 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge @Override public String getRule() { StringBuilder sb = new StringBuilder(); - String prefix; - if (abilityWord != null) { - prefix = abilityWord.formatWord(); - } else if (flavorWord != null) { - prefix = CardUtil.italicizeWithEmDash(flavorWord); - } else { - prefix = ""; - } - sb.append(prefix); - sb.append(triggerPhrase == null ? "" : triggerPhrase); if (interveningIfCondition != null) { @@ -376,7 +366,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge sb.append(" Do this only once each turn."); } } - return sb.toString(); + return addRulePrefix(sb.toString()); } private static boolean startsWithVerb(String ruleLow) { diff --git a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAbility.java b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAbility.java index fad90076953..231e5dd9a1d 100644 --- a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAbility.java +++ b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAbility.java @@ -6,7 +6,6 @@ import mage.abilities.condition.Condition; import mage.abilities.effects.Effect; import mage.abilities.effects.EntersBattlefieldEffect; import mage.constants.Zone; -import mage.util.CardUtil; /** * @author BetaSteward_at_googlemail.com @@ -81,19 +80,8 @@ public class EntersBattlefieldAbility extends StaticAbility { return abilityRule; } String superRule = super.getRule(); - String prefix; - if (abilityWord != null) { - prefix = abilityWord.formatWord(); - } else if (flavorWord != null) { - prefix = CardUtil.italicizeWithEmDash(flavorWord); - } else { - prefix = null; - } String rule = (optional ? "you may have " : "") + "{this} enter" + (optional ? "" : "s") + (!superRule.isEmpty() && superRule.charAt(0) == ' ' ? "" : " ") + superRule; - if (prefix != null) { - return prefix + CardUtil.getTextWithFirstCharUpperCase(rule); - } - return rule; + return addRulePrefix(rule); } } diff --git a/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java b/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java index 6a5245ccc44..67d2f1cce87 100644 --- a/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java @@ -9,10 +9,8 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; import mage.abilities.hint.Hint; import mage.constants.EffectType; -import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.util.CardUtil; import mage.watchers.Watcher; import java.util.ArrayList; @@ -83,9 +81,7 @@ public class ConditionalInterveningIfTriggeredAbility extends TriggeredAbilityIm if (abilityText == null || abilityText.isEmpty()) { return ability.getRule(); } - return (flavorWord != null ? CardUtil.italicizeWithEmDash(flavorWord) : "") + - (abilityWord != null ? abilityWord.formatWord() : "") + - abilityText + (abilityText.endsWith(".") || abilityText.endsWith("\"") || abilityText.endsWith(">") ? "" : "."); + return addRulePrefix(abilityText + (abilityText.endsWith(".") || abilityText.endsWith("\"") || abilityText.endsWith(">") ? "" : ".")); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChooseCreatureEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChooseCreatureEffect.java index a88e729a4da..f3eba38d1c1 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChooseCreatureEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChooseCreatureEffect.java @@ -29,7 +29,7 @@ public class ChooseCreatureEffect extends OneShotEffect { public ChooseCreatureEffect(FilterPermanent filter, boolean useOffset) { super(Outcome.Benefit); this.filter = filter; - this.staticText = "choose " + filter.getMessage(); + this.staticText = "choose " + CardUtil.addArticle(filter.getMessage()); this.useOffset = useOffset; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileSourceAndReturnFaceUpEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileSourceAndReturnFaceUpEffect.java index 3743f977029..d9657b3ee5f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileSourceAndReturnFaceUpEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileSourceAndReturnFaceUpEffect.java @@ -10,7 +10,7 @@ public class ExileSourceAndReturnFaceUpEffect extends ExileAndReturnSourceEffect public ExileSourceAndReturnFaceUpEffect() { super(PutCards.BATTLEFIELD, Pronoun.IT, true, null); - staticText = "exile {this}, then return it to the battlefield. (front face up)"; + staticText = "exile {this}, then return it to the battlefield (front face up)."; } private ExileSourceAndReturnFaceUpEffect(final ExileSourceAndReturnFaceUpEffect effect) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/MayCastTargetCardEffect.java b/Mage/src/main/java/mage/abilities/effects/common/MayCastTargetCardEffect.java index 0953892768b..121949db9ed 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/MayCastTargetCardEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/MayCastTargetCardEffect.java @@ -156,7 +156,11 @@ public class MayCastTargetCardEffect extends OneShotEffect { } text += "."; if (thenExile) { - text += " " + ThatSpellGraveyardExileReplacementEffect.RULE_YOUR; + if (text.contains("a graveyard")) { + text += " " + ThatSpellGraveyardExileReplacementEffect.RULE_A; + } else { + text += " " + ThatSpellGraveyardExileReplacementEffect.RULE_YOUR; + } } return text; } diff --git a/Mage/src/main/java/mage/abilities/keyword/EquipAbility.java b/Mage/src/main/java/mage/abilities/keyword/EquipAbility.java index 76b469d2e59..a9457f751ed 100644 --- a/Mage/src/main/java/mage/abilities/keyword/EquipAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/EquipAbility.java @@ -88,7 +88,7 @@ public class EquipAbility extends ActivatedAbilityImpl { String targetText = getTargets().get(0) != null ? getTargets().get(0).getFilter().getMessage() : "creature"; String reminderText = " (" + getManaCosts().getText() + ": Attach to target " + targetText + ". Equip only as a sorcery.)"; - StringBuilder sb = new StringBuilder("Equip"); + StringBuilder sb = new StringBuilder(addRulePrefix("Equip")); if (!targetText.equals("creature you control")) { sb.append(' ').append(targetText); } diff --git a/Mage/src/main/java/mage/abilities/keyword/ProtectionAbility.java b/Mage/src/main/java/mage/abilities/keyword/ProtectionAbility.java index 913b9d7c9d1..3fc0f7e1335 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ProtectionAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ProtectionAbility.java @@ -81,8 +81,8 @@ public class ProtectionAbility extends StaticAbility { if (this.staticText != null && !this.staticText.isEmpty()) { return this.staticText; } - return (flavorWord == null ? "protection from " : CardUtil.italicizeWithEmDash(flavorWord) + "Protection from ") - + filter.getMessage() + (removeAuras ? "" : ". This effect doesn't remove Auras."); + return addRulePrefix("protection from ") + filter.getMessage() + + (removeAuras ? "" : ". This effect doesn't remove Auras."); } public ProtectionAbility setText(String text) { diff --git a/Mage/src/main/java/mage/game/stack/StackAbility.java b/Mage/src/main/java/mage/game/stack/StackAbility.java index b79e974e14a..a880c666afa 100644 --- a/Mage/src/main/java/mage/game/stack/StackAbility.java +++ b/Mage/src/main/java/mage/game/stack/StackAbility.java @@ -583,6 +583,11 @@ public class StackAbility extends StackObjectImpl implements Ability { throw new UnsupportedOperationException("Not supported."); } + @Override + public String addRulePrefix(String rule) { + throw new UnsupportedOperationException("Not supported."); + } + @Override public Ability withFirstModeFlavorWord(String flavorWord) { throw new UnsupportedOperationException("Not supported.");