From e5a351ff58c70b39ec0249f028346dfd5790a392 Mon Sep 17 00:00:00 2001 From: Grath <1895280+Grath@users.noreply.github.com> Date: Sun, 29 Sep 2024 13:12:31 -0400 Subject: [PATCH] [DSC] Implement The Lord of Pain. (#12940) Also adds "their" to the text that CardUtil.addArticle supports and fixes a range of influence bug in SpellCastAllTriggeredAbility. --- Mage.Sets/src/mage/cards/t/TheLordOfPain.java | 141 ++++++++++++++++++ .../sets/DuskmournHouseOfHorrorCommander.java | 1 + .../common/SpellCastAllTriggeredAbility.java | 3 +- Mage/src/main/java/mage/util/CardUtil.java | 1 + 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 Mage.Sets/src/mage/cards/t/TheLordOfPain.java diff --git a/Mage.Sets/src/mage/cards/t/TheLordOfPain.java b/Mage.Sets/src/mage/cards/t/TheLordOfPain.java new file mode 100644 index 00000000000..470a4556562 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheLordOfPain.java @@ -0,0 +1,141 @@ +package mage.cards.t; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.SpellCastAllTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.CantGainLifeAllEffect; +import mage.constants.*; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.filter.FilterPlayer; +import mage.filter.FilterSpell; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.MageObjectReferencePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.targetpointer.FixedTarget; +import mage.watchers.common.SpellsCastWatcher; + +/** + * + * @author Grath + */ +public final class TheLordOfPain extends CardImpl { + public TheLordOfPain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Menace + this.addAbility(new MenaceAbility(false)); + + // Your opponents can't gain life. + this.addAbility(new SimpleStaticAbility( + new CantGainLifeAllEffect(Duration.WhileOnBattlefield, TargetController.OPPONENT) + )); + + // Whenever a player casts their first spell each turn, choose another target player. The Lord of Pain deals damage equal to that spell's mana value to the chosen player. + this.addAbility(new TheLordOfPainTriggeredAbility()); + } + + private TheLordOfPain(final TheLordOfPain card) { + super(card); + } + + @Override + public TheLordOfPain copy() { + return new TheLordOfPain(this); + } +} + +enum TheLordOfPainPredicate implements Predicate { + instance; + + @Override + public boolean apply(StackObject input, Game game) { + return game.getState() + .getWatcher(SpellsCastWatcher.class) + .getCount(input.getControllerId()) == 1; + } +} + +class TheLordOfPainTriggeredAbility extends SpellCastAllTriggeredAbility { + private static final FilterSpell filter = new FilterSpell("their first spell each turn"); + + static { + filter.add(TheLordOfPainPredicate.instance); + } + + public TheLordOfPainTriggeredAbility() { + super(new TheLordOfPainEffect(), filter, false, SetTargetPointer.PLAYER); + } + + protected TheLordOfPainTriggeredAbility(final TheLordOfPainTriggeredAbility ability) { + super(ability); + } + + @Override + public TheLordOfPainTriggeredAbility copy() { + return new TheLordOfPainTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (super.checkTrigger(event, game)) { + Player controller = game.getPlayer(getControllerId()); + Spell spell = (Spell)getEffects().get(0).getValue("spellCast"); + if (controller != null) { + FilterPlayer filter2 = new FilterPlayer("another target player"); + filter2.add(Predicates.not(new MageObjectReferencePredicate(spell.getControllerId(), game))); + TargetPlayer target = new TargetPlayer(1, 1, false, filter2); + controller.choose(Outcome.Damage, target, this, game); + getEffects().setTargetPointer(new FixedTarget(target.getFirstTarget())); + return true; + } + } + return false; + } +} + +class TheLordOfPainEffect extends OneShotEffect { + + TheLordOfPainEffect() { + super(Outcome.Benefit); + staticText = "choose another target player. {this} deals damage equal to that spell's mana value to the chosen player"; + } + + private TheLordOfPainEffect(final TheLordOfPainEffect effect) { + super(effect); + } + + @Override + public TheLordOfPainEffect copy() { + return new TheLordOfPainEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = (Spell)this.getValue("spellCast"); + if (spell != null) { + int cost = spell.getManaValue(); + Player target = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (target != null) { + target.damage(cost, source.getSourceId(), source, game); + return true; + } + } + return false; } +} diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java index 0c83af0054a..aefc2b6eddb 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java @@ -257,6 +257,7 @@ public final class DuskmournHouseOfHorrorCommander extends ExpansionSet { cards.add(new SetCardInfo("Temur War Shaman", 200, Rarity.RARE, mage.cards.t.TemurWarShaman.class)); cards.add(new SetCardInfo("Terminus", 70, Rarity.RARE, mage.cards.t.Terminus.class)); cards.add(new SetCardInfo("The Eldest Reborn", 139, Rarity.UNCOMMON, mage.cards.t.TheEldestReborn.class)); + cards.add(new SetCardInfo("The Lord of Pain", 3, Rarity.MYTHIC, mage.cards.t.TheLordOfPain.class)); cards.add(new SetCardInfo("Theater of Horrors", 236, Rarity.RARE, mage.cards.t.TheaterOfHorrors.class)); cards.add(new SetCardInfo("They Came from the Pipes", 14, Rarity.RARE, mage.cards.t.TheyCameFromThePipes.class)); cards.add(new SetCardInfo("Thirst for Meaning", 129, Rarity.COMMON, mage.cards.t.ThirstForMeaning.class)); diff --git a/Mage/src/main/java/mage/abilities/common/SpellCastAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/SpellCastAllTriggeredAbility.java index b14269dd126..957b9d9038e 100644 --- a/Mage/src/main/java/mage/abilities/common/SpellCastAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/SpellCastAllTriggeredAbility.java @@ -60,7 +60,8 @@ public class SpellCastAllTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Spell spell = game.getStack().getSpell(event.getTargetId()); - if (!filter.match(spell, getControllerId(), this, game)) { + if (!filter.match(spell, getControllerId(), this, game) + || !game.getState().getPlayersInRange(getControllerId(), game, false).contains(event.getPlayerId())) { return false; } getEffects().setValue("spellCast", spell); diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index 49742ab086d..a8d3413762e 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -1032,6 +1032,7 @@ public final class CardUtil { || text.startsWith("any ") || text.startsWith("{this} ") || text.startsWith("your ") + || text.startsWith("their ") || text.startsWith("one ")) { return text; }