From ee60325c072d195483d937010e1e8a0d39537042 Mon Sep 17 00:00:00 2001 From: Susucre <34709007+Susucre@users.noreply.github.com> Date: Sun, 5 Nov 2023 15:38:02 +0100 Subject: [PATCH] [LCI] Implement Preacher of the Schism --- .../src/mage/cards/p/PreacherOfTheSchism.java | 127 ++++++++++++++++++ .../src/mage/cards/s/ScourgeOfTheThrone.java | 50 ++----- .../src/mage/sets/TheLostCavernsOfIxalan.java | 1 + ...eAttackingPlayerWithMostLifeCondition.java | 36 +++++ .../abilities/keyword/DethroneAbility.java | 30 ++--- .../other/PlayerWithTheMostLifePredicate.java | 32 +++++ 6 files changed, 216 insertions(+), 60 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/p/PreacherOfTheSchism.java create mode 100644 Mage/src/main/java/mage/abilities/condition/common/SourceAttackingPlayerWithMostLifeCondition.java create mode 100644 Mage/src/main/java/mage/filter/predicate/other/PlayerWithTheMostLifePredicate.java diff --git a/Mage.Sets/src/mage/cards/p/PreacherOfTheSchism.java b/Mage.Sets/src/mage/cards/p/PreacherOfTheSchism.java new file mode 100644 index 00000000000..a38b0d926bf --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PreacherOfTheSchism.java @@ -0,0 +1,127 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.other.PlayerWithTheMostLifePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.token.IxalanVampireToken; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author Susucr + */ +public final class PreacherOfTheSchism extends CardImpl { + + public PreacherOfTheSchism(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // Whenever Preacher of the Schism attacks the player with the most life or tied for most life, create a 1/1 white Vampire creature token with lifelink. + this.addAbility(new PreacherOfTheSchismFirstTrigger()); + + // Whenever Preacher of the Schism attacks while you have the most life or are tied for most life, you draw a card and you lose 1 life. + this.addAbility(new PreacherOfTheSchismSecondTrigger()); + } + + private PreacherOfTheSchism(final PreacherOfTheSchism card) { + super(card); + } + + @Override + public PreacherOfTheSchism copy() { + return new PreacherOfTheSchism(this); + } +} + +class PreacherOfTheSchismFirstTrigger extends TriggeredAbilityImpl { + + public PreacherOfTheSchismFirstTrigger() { + super(Zone.BATTLEFIELD, new CreateTokenEffect(new IxalanVampireToken()), false); + setTriggerPhrase("Whenever {this} attacks the player with the most life or tied for most life, "); + } + + protected PreacherOfTheSchismFirstTrigger(final PreacherOfTheSchismFirstTrigger ability) { + super(ability); + } + + @Override + public PreacherOfTheSchismFirstTrigger copy() { + return new PreacherOfTheSchismFirstTrigger(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + UUID defenderId = game.getCombat().getDefenderId(getSourceId()); + if (defenderId == null) { + return false; + } + + Player attackedPlayer = game.getPlayer(defenderId); + return PlayerWithTheMostLifePredicate.instance.apply( + new ObjectSourcePlayer<>(attackedPlayer, getControllerId(), null), + game + ); + } +} + +class PreacherOfTheSchismSecondTrigger extends TriggeredAbilityImpl { + + public PreacherOfTheSchismSecondTrigger() { + super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1, "you"), false); + this.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")); + setTriggerPhrase("Whenever {this} attacks while you have the most life or are tied for most life, "); + } + + protected PreacherOfTheSchismSecondTrigger(final PreacherOfTheSchismSecondTrigger ability) { + super(ability); + } + + @Override + public PreacherOfTheSchismSecondTrigger copy() { + return new PreacherOfTheSchismSecondTrigger(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + UUID defenderId = game.getCombat().getDefenderId(getSourceId()); + if (defenderId == null) { // Checks that {this} is attacking. + return false; + } + + Player controller = game.getPlayer(getControllerId()); + return PlayerWithTheMostLifePredicate.instance.apply( + new ObjectSourcePlayer<>(controller, getControllerId(), null), + game + ); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ScourgeOfTheThrone.java b/Mage.Sets/src/mage/cards/s/ScourgeOfTheThrone.java index 4c85314fd53..6cec7f8d873 100644 --- a/Mage.Sets/src/mage/cards/s/ScourgeOfTheThrone.java +++ b/Mage.Sets/src/mage/cards/s/ScourgeOfTheThrone.java @@ -1,12 +1,10 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.TriggeredAbility; import mage.abilities.common.AttacksFirstTimeTriggeredAbility; -import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceAttackingPlayerWithMostLifeCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.AdditionalCombatPhaseEffect; import mage.abilities.effects.common.UntapAllControllerEffect; @@ -17,11 +15,10 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class ScourgeOfTheThrone extends CardImpl { @@ -47,11 +44,11 @@ public final class ScourgeOfTheThrone extends CardImpl { ability.addEffect(new AdditionalCombatPhaseEffect()); this.addAbility(new ConditionalInterveningIfTriggeredAbility( ability, - ScourgeOfTheThroneCondition.instance, + SourceAttackingPlayerWithMostLifeCondition.instance, "Whenever {this} attacks for the first time each turn, " - + "if it's attacking the player with the most life or tied for most life, " - + "untap all attacking creatures. After this phase, " - + "there is an additional combat phase." + + "if it's attacking the player with the most life or tied for most life, " + + "untap all attacking creatures. After this phase, " + + "there is an additional combat phase." )); } @@ -63,35 +60,4 @@ public final class ScourgeOfTheThrone extends CardImpl { public ScourgeOfTheThrone copy() { return new ScourgeOfTheThrone(this); } -} - -enum ScourgeOfTheThroneCondition implements Condition { - - instance; - - @Override - public boolean apply(Game game, Ability source) { - UUID defenderId = game.getCombat().getDefenderId(source.getSourceId()); - if (defenderId != null) { - Player attackedPlayer = game.getPlayer(defenderId); - Player controller = game.getPlayer(source.getControllerId()); - if (attackedPlayer != null && controller != null) { - int mostLife = Integer.MIN_VALUE; - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null && player.getLife() > mostLife) { - mostLife = player.getLife(); - } - } - return attackedPlayer.getLife() == mostLife; - } - } - return false; - } - - @Override - public String toString() { - return "{this} is attacking the player with the most life or tied for most life"; - } - -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java index f3af8fd8340..9353c607e49 100644 --- a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java @@ -230,6 +230,7 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Plundering Pirate", 160, Rarity.COMMON, mage.cards.p.PlunderingPirate.class)); cards.add(new SetCardInfo("Poetic Ingenuity", 161, Rarity.RARE, mage.cards.p.PoeticIngenuity.class)); cards.add(new SetCardInfo("Poison Dart Frog", 207, Rarity.COMMON, mage.cards.p.PoisonDartFrog.class)); + cards.add(new SetCardInfo("Preacher of the Schism", 113, Rarity.RARE, mage.cards.p.PreacherOfTheSchism.class)); cards.add(new SetCardInfo("Primordial Gnawer", 114, Rarity.COMMON, mage.cards.p.PrimordialGnawer.class)); cards.add(new SetCardInfo("Promising Vein", 279, Rarity.COMMON, mage.cards.p.PromisingVein.class)); cards.add(new SetCardInfo("Pugnacious Hammerskull", 208, Rarity.RARE, mage.cards.p.PugnaciousHammerskull.class)); diff --git a/Mage/src/main/java/mage/abilities/condition/common/SourceAttackingPlayerWithMostLifeCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SourceAttackingPlayerWithMostLifeCondition.java new file mode 100644 index 00000000000..7d066f2e29b --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/SourceAttackingPlayerWithMostLifeCondition.java @@ -0,0 +1,36 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.other.PlayerWithTheMostLifePredicate; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author Susucr + */ +public enum SourceAttackingPlayerWithMostLifeCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + UUID defenderId = game.getCombat().getDefenderId(source.getSourceId()); + if (defenderId == null) { + return false; + } + + Player attackedPlayer = game.getPlayer(defenderId); + return PlayerWithTheMostLifePredicate.instance.apply( + new ObjectSourcePlayer<>(attackedPlayer, source.getControllerId(), source), + game + ); + } + + @Override + public String toString() { + return "{this} is attacking the player with the most life or tied for most life"; + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/DethroneAbility.java b/Mage/src/main/java/mage/abilities/keyword/DethroneAbility.java index 77b6613da96..bac5777c20d 100644 --- a/Mage/src/main/java/mage/abilities/keyword/DethroneAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/DethroneAbility.java @@ -1,16 +1,18 @@ package mage.abilities.keyword; -import java.util.UUID; - import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.constants.Zone; import mage.counters.CounterType; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.other.PlayerWithTheMostLifePredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; +import java.util.UUID; + /** * Dethrone triggers whenever a creature with dethrone attacks the player with * the most life or tied for the most life. When the ability resolves, you put a @@ -48,23 +50,15 @@ public class DethroneAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { UUID defenderId = game.getCombat().getDefenderId(getSourceId()); - if (defenderId != null) { - Player attackedPlayer = game.getPlayer(defenderId); - Player controller = game.getPlayer(getControllerId()); - if (attackedPlayer != null && controller != null) { - int mostLife = Integer.MIN_VALUE; - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - if (player.getLife() > mostLife) { - mostLife = player.getLife(); - } - } - } - return attackedPlayer.getLife() == mostLife; - } + if (defenderId == null) { + return false; } - return false; + + Player attackedPlayer = game.getPlayer(defenderId); + return PlayerWithTheMostLifePredicate.instance.apply( + new ObjectSourcePlayer<>(attackedPlayer, getControllerId(), null), + game + ); } @Override diff --git a/Mage/src/main/java/mage/filter/predicate/other/PlayerWithTheMostLifePredicate.java b/Mage/src/main/java/mage/filter/predicate/other/PlayerWithTheMostLifePredicate.java new file mode 100644 index 00000000000..d908887fd0c --- /dev/null +++ b/Mage/src/main/java/mage/filter/predicate/other/PlayerWithTheMostLifePredicate.java @@ -0,0 +1,32 @@ +package mage.filter.predicate.other; + +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author Susucr + */ +public enum PlayerWithTheMostLifePredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + Player inputPlayer = input.getObject(); + if (inputPlayer == null) { + return false; + } + + int mostLife = Integer.MIN_VALUE; + for (UUID playerId : game.getState().getPlayersInRange(input.getPlayerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null && player.getLife() > mostLife) { + mostLife = player.getLife(); + } + } + return inputPlayer.getLife() == mostLife; + } +}