From 5ddb69e1ba6a71a2ad9df12133b990e2f58f0d39 Mon Sep 17 00:00:00 2001 From: Vivian Greenslade Date: Wed, 30 Aug 2023 21:17:52 -0230 Subject: [PATCH] Rework DealCombatDamageControlled to allow a creature filter (#11037) * Added filter to ability * wip * updated logic for trigger to use new event * updated classes using trigger to account for constructor changes * condensed constructors, added total damage dealt as value, added exception for SetTargetPointer * fixed set value * fixed optional flag on cards * fixed filter --- .../src/mage/cards/d/DescendantsFury.java | 4 +- .../src/mage/cards/f/FeywildVisitor.java | 60 +------------ .../src/mage/cards/k/KaitoDancingShadow.java | 2 +- .../src/mage/cards/k/KeeperOfFables.java | 71 +++------------ Mage.Sets/src/mage/cards/n/NaturesWill.java | 4 +- .../src/mage/cards/p/ProsperousThief.java | 73 +++------------- .../src/mage/cards/p/PyrewildShaman.java | 5 +- .../src/mage/cards/s/StrongholdArena.java | 6 +- .../src/mage/cards/t/ThopterSpyNetwork.java | 60 ++----------- .../src/mage/cards/t/ThunderbladeCharge.java | 12 ++- ...ombatDamageControlledTriggeredAbility.java | 87 +++++++++---------- .../emblems/LolthSpiderQueenEmblem.java | 4 +- 12 files changed, 98 insertions(+), 290 deletions(-) diff --git a/Mage.Sets/src/mage/cards/d/DescendantsFury.java b/Mage.Sets/src/mage/cards/d/DescendantsFury.java index 3ec8c6e2f33..b2442d0845e 100644 --- a/Mage.Sets/src/mage/cards/d/DescendantsFury.java +++ b/Mage.Sets/src/mage/cards/d/DescendantsFury.java @@ -10,6 +10,7 @@ import mage.abilities.effects.common.DoIfCostPaid; import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.SetTargetPointer; import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate; @@ -32,12 +33,11 @@ public final class DescendantsFury extends CardImpl { // Whenever one or more creatures you control deal combat damage to a player, you may sacrifice one of them. If you do, reveal cards from the top of your library until you reveal a creature card that shares a creature type with the sacrificed creature. Put that card onto the battlefield and the rest on the bottom of your library in a random order. Ability ability = new DealCombatDamageControlledTriggeredAbility( - Zone.BATTLEFIELD, new DoIfCostPaid( new DescendantsFuryEffect(), new DescendantsFurySacrificeCost() ), - true + SetTargetPointer.PLAYER ); ability.addWatcher(new DamagedPlayerThisCombatWatcher()); diff --git a/Mage.Sets/src/mage/cards/f/FeywildVisitor.java b/Mage.Sets/src/mage/cards/f/FeywildVisitor.java index 3c4b24014a1..ca3742eb141 100644 --- a/Mage.Sets/src/mage/cards/f/FeywildVisitor.java +++ b/Mage.Sets/src/mage/cards/f/FeywildVisitor.java @@ -1,6 +1,6 @@ package mage.cards.f; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DealCombatDamageControlledTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; @@ -8,15 +8,8 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.game.permanent.PermanentToken; import mage.game.permanent.token.FaerieDragonToken; -import java.util.ArrayList; -import java.util.List; import java.util.UUID; /** @@ -32,7 +25,8 @@ public final class FeywildVisitor extends CardImpl { // Commander creatures you own have "Whenever one or more nontoken creatures you control deal combat damage to a player, you create a 1/1 blue Faerie Dragon creature token with flying." this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( - new FeywildVisitorAbility(), Duration.WhileOnBattlefield, + new DealCombatDamageControlledTriggeredAbility(new CreateTokenEffect(new FaerieDragonToken()), StaticFilters.FILTER_CREATURE_NON_TOKEN), + Duration.WhileOnBattlefield, StaticFilters.FILTER_CREATURES_OWNED_COMMANDER ))); } @@ -45,50 +39,4 @@ public final class FeywildVisitor extends CardImpl { public FeywildVisitor copy() { return new FeywildVisitor(this); } -} - -class FeywildVisitorAbility extends TriggeredAbilityImpl { - - private final List damagedPlayerIds = new ArrayList<>(); - - FeywildVisitorAbility() { - super(Zone.BATTLEFIELD, new CreateTokenEffect(new FaerieDragonToken()), false); - setTriggerPhrase("Whenever one or more nontoken creatures you control deal combat damage to a player, you "); - } - - private FeywildVisitorAbility(final FeywildVisitorAbility ability) { - super(ability); - } - - @Override - public FeywildVisitorAbility copy() { - return new FeywildVisitorAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER - || event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_POST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_POST) { - damagedPlayerIds.clear(); - return false; - } - if (event.getType() != GameEvent.EventType.DAMAGED_PLAYER - || !((DamagedPlayerEvent) event).isCombatDamage()) { - return false; - } - Permanent creature = game.getPermanent(event.getSourceId()); - if (creature == null - || !creature.isControlledBy(getControllerId()) - || creature instanceof PermanentToken - || damagedPlayerIds.contains(event.getTargetId())) { - return false; - } - damagedPlayerIds.add(event.getTargetId()); - return true; - } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/k/KaitoDancingShadow.java b/Mage.Sets/src/mage/cards/k/KaitoDancingShadow.java index 96aa035fc3a..a1567c99bef 100644 --- a/Mage.Sets/src/mage/cards/k/KaitoDancingShadow.java +++ b/Mage.Sets/src/mage/cards/k/KaitoDancingShadow.java @@ -39,7 +39,7 @@ public final class KaitoDancingShadow extends CardImpl { this.setStartingLoyalty(3); // Whenever one or more creatures you control deal combat damage to a player, you may return one of them to its owner's hand. If you do, you may activate loyalty abilities of Kaito twice this turn rather than only once. - Ability ability = new DealCombatDamageControlledTriggeredAbility(Zone.BATTLEFIELD, new KaitoDancingShadowEffect(), true); + Ability ability = new DealCombatDamageControlledTriggeredAbility(new KaitoDancingShadowEffect(), SetTargetPointer.PLAYER); ability.addWatcher(new DamagedPlayerThisCombatWatcher()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/k/KeeperOfFables.java b/Mage.Sets/src/mage/cards/k/KeeperOfFables.java index 097f560cffd..a0e8ba955ee 100644 --- a/Mage.Sets/src/mage/cards/k/KeeperOfFables.java +++ b/Mage.Sets/src/mage/cards/k/KeeperOfFables.java @@ -1,20 +1,14 @@ package mage.cards.k; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DealCombatDamageControlledTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; - -import java.util.ArrayList; -import java.util.List; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; import java.util.UUID; /** @@ -22,6 +16,12 @@ import java.util.UUID; */ public final class KeeperOfFables extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Human creatures"); + + static { + filter.add(Predicates.not(SubType.HUMAN.getPredicate())); + } + public KeeperOfFables(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); @@ -30,7 +30,7 @@ public final class KeeperOfFables extends CardImpl { this.toughness = new MageInt(5); // Whenever one or more non-Human creatures you control deal combat damage to a player, draw a card. - this.addAbility(new KeeperOfFablesTriggeredAbility()); + this.addAbility(new DealCombatDamageControlledTriggeredAbility(new DrawCardSourceControllerEffect(1), filter)); } private KeeperOfFables(final KeeperOfFables card) { @@ -41,53 +41,4 @@ public final class KeeperOfFables extends CardImpl { public KeeperOfFables copy() { return new KeeperOfFables(this); } -} - -class KeeperOfFablesTriggeredAbility extends TriggeredAbilityImpl { - - private final List damagedPlayerIds = new ArrayList<>(); - - KeeperOfFablesTriggeredAbility() { - super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), false); - } - - private KeeperOfFablesTriggeredAbility(final KeeperOfFablesTriggeredAbility ability) { - super(ability); - } - - @Override - public KeeperOfFablesTriggeredAbility copy() { - return new KeeperOfFablesTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER - || event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_POST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.DAMAGED_PLAYER) { - if (((DamagedPlayerEvent) event).isCombatDamage()) { - Permanent creature = game.getPermanent(event.getSourceId()); - if (creature != null - && creature.isControlledBy(controllerId) - && !creature.hasSubtype(SubType.HUMAN, game) - && !damagedPlayerIds.contains(event.getTargetId())) { - damagedPlayerIds.add(event.getTargetId()); - return true; - } - } - } - if (event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_POST) { - damagedPlayerIds.clear(); - } - return false; - } - - @Override - public String getRule() { - return "Whenever one or more non-Human creatures you control deal combat damage to a player, draw a card."; - } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/n/NaturesWill.java b/Mage.Sets/src/mage/cards/n/NaturesWill.java index c16573e9c86..78e922d58b6 100644 --- a/Mage.Sets/src/mage/cards/n/NaturesWill.java +++ b/Mage.Sets/src/mage/cards/n/NaturesWill.java @@ -10,7 +10,7 @@ import mage.abilities.effects.common.UntapAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; +import mage.constants.SetTargetPointer; import mage.filter.StaticFilters; /** @@ -25,7 +25,7 @@ public final class NaturesWill extends CardImpl { // Whenever one or more creatures you control deal combat damage to a player, tap all lands that player controls and untap all lands you control. Effect tapAllEffect = new TapAllTargetPlayerControlsEffect(StaticFilters.FILTER_LANDS); tapAllEffect.setText("tap all lands that player controls"); - Ability ability = new DealCombatDamageControlledTriggeredAbility(Zone.BATTLEFIELD, tapAllEffect, true); + Ability ability = new DealCombatDamageControlledTriggeredAbility(tapAllEffect, SetTargetPointer.PLAYER); ability.addEffect(new UntapAllEffect(StaticFilters.FILTER_CONTROLLED_PERMANENT_LANDS).concatBy("and")); addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/ProsperousThief.java b/Mage.Sets/src/mage/cards/p/ProsperousThief.java index 075be9d3f52..c1ffc842f26 100644 --- a/Mage.Sets/src/mage/cards/p/ProsperousThief.java +++ b/Mage.Sets/src/mage/cards/p/ProsperousThief.java @@ -1,22 +1,17 @@ package mage.cards.p; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DealCombatDamageControlledTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.NinjutsuAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; import mage.game.permanent.token.TreasureToken; -import java.util.ArrayList; -import java.util.List; import java.util.UUID; /** @@ -24,6 +19,12 @@ import java.util.UUID; */ public final class ProsperousThief extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Ninja or Rogue creatures"); + + static { + filter.add(Predicates.or(SubType.NINJA.getPredicate(), SubType.ROGUE.getPredicate())); + } + public ProsperousThief(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); @@ -36,7 +37,7 @@ public final class ProsperousThief extends CardImpl { this.addAbility(new NinjutsuAbility("{1}{U}")); // Whenever one or more Ninja or Rogue creatures you control deal combat damage to a player, create a Treasure token. - this.addAbility(new ProsperousThiefTriggeredAbility()); + this.addAbility(new DealCombatDamageControlledTriggeredAbility(new CreateTokenEffect(new TreasureToken()), filter)); } private ProsperousThief(final ProsperousThief card) { @@ -47,56 +48,4 @@ public final class ProsperousThief extends CardImpl { public ProsperousThief copy() { return new ProsperousThief(this); } -} - -class ProsperousThiefTriggeredAbility extends TriggeredAbilityImpl { - - private final List damagedPlayerIds = new ArrayList<>(); - - ProsperousThiefTriggeredAbility() { - super(Zone.BATTLEFIELD, new CreateTokenEffect(new TreasureToken()), false); - } - - private ProsperousThiefTriggeredAbility(final ProsperousThiefTriggeredAbility ability) { - super(ability); - } - - @Override - public ProsperousThiefTriggeredAbility copy() { - return new ProsperousThiefTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER - || event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_POST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_POST) { - damagedPlayerIds.clear(); - return false; - } - if (event.getType() != GameEvent.EventType.DAMAGED_PLAYER - || !((DamagedPlayerEvent) event).isCombatDamage() - || damagedPlayerIds.contains(event.getTargetId())) { - return false; - } - Permanent creature = game.getPermanent(event.getSourceId()); - if (creature == null - || !isControlledBy(creature.getControllerId()) - || (!creature.hasSubtype(SubType.NINJA, game) - && !creature.hasSubtype(SubType.ROGUE, game))) { - return false; - } - damagedPlayerIds.add(event.getTargetId()); - return true; - } - - @Override - public String getRule() { - return "Whenever one or more Ninja or Rogue creatures you control " + - "deal combat damage to a player, create a Treasure token."; - } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/p/PyrewildShaman.java b/Mage.Sets/src/mage/cards/p/PyrewildShaman.java index 2b593c1b06b..443344c0747 100644 --- a/Mage.Sets/src/mage/cards/p/PyrewildShaman.java +++ b/Mage.Sets/src/mage/cards/p/PyrewildShaman.java @@ -13,8 +13,10 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.SetTargetPointer; import mage.constants.SubType; import mage.constants.Zone; +import mage.filter.StaticFilters; public final class PyrewildShaman extends CardImpl { @@ -32,7 +34,8 @@ public final class PyrewildShaman extends CardImpl { // Whenever one or more creatures you control deal combat damage to a player, if Pyrewild Shaman is in your graveyard, you may pay {3}. If you do, return Pyrewild Shaman to your hand. this.addAbility(new DealCombatDamageControlledTriggeredAbility(Zone.GRAVEYARD, new DoIfCostPaid(new ReturnToHandSourceEffect(), new ManaCostsImpl<>("{3}")) - .setText("if {this} is in your graveyard, you may pay {3}. If you do, return {this} to your hand"))); + .setText("if {this} is in your graveyard, you may pay {3}. If you do, return {this} to your hand"), + StaticFilters.FILTER_PERMANENT_CREATURES, SetTargetPointer.NONE, false)); } diff --git a/Mage.Sets/src/mage/cards/s/StrongholdArena.java b/Mage.Sets/src/mage/cards/s/StrongholdArena.java index 75cec25506b..db436225982 100644 --- a/Mage.Sets/src/mage/cards/s/StrongholdArena.java +++ b/Mage.Sets/src/mage/cards/s/StrongholdArena.java @@ -13,7 +13,9 @@ import mage.cards.CardSetInfo; import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.SetTargetPointer; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; @@ -36,9 +38,7 @@ public final class StrongholdArena extends CardImpl { // Whenever one or more creatures you control deal combat damage to a player, you may reveal the top card of your library and put it into your hand. // If you do, you lose life equal to its mana value. - this.addAbility(new DealCombatDamageControlledTriggeredAbility( - Zone.BATTLEFIELD, new StrongholdArenaDrawEffect(), false, false, true - )); + this.addAbility(new DealCombatDamageControlledTriggeredAbility(Zone.BATTLEFIELD, new StrongholdArenaDrawEffect(), StaticFilters.FILTER_PERMANENT_CREATURES, SetTargetPointer.NONE, true)); } private StrongholdArena(final StrongholdArena card) { diff --git a/Mage.Sets/src/mage/cards/t/ThopterSpyNetwork.java b/Mage.Sets/src/mage/cards/t/ThopterSpyNetwork.java index feb59d0f8e1..7f75c371c35 100644 --- a/Mage.Sets/src/mage/cards/t/ThopterSpyNetwork.java +++ b/Mage.Sets/src/mage/cards/t/ThopterSpyNetwork.java @@ -2,21 +2,20 @@ package mage.cards.t; import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DealCombatDamageControlledTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; +import mage.filter.common.FilterArtifactCreaturePermanent; import mage.filter.common.FilterArtifactPermanent; +import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; import mage.game.permanent.token.ThopterColorlessToken; -import java.util.ArrayList; -import java.util.List; import java.util.UUID; /** @@ -24,6 +23,8 @@ import java.util.UUID; */ public final class ThopterSpyNetwork extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterArtifactCreaturePermanent("artifact creatures"); + public ThopterSpyNetwork(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}"); @@ -31,7 +32,7 @@ public final class ThopterSpyNetwork extends CardImpl { this.addAbility(new ThopterSpyNetworkUpkeepTriggeredAbility()); // Whenever one or more artifact creatures you control deals combat damage to a player, draw a card. - this.addAbility(new ThopterSpyNetworkDamageTriggeredAbility()); + this.addAbility(new DealCombatDamageControlledTriggeredAbility(new DrawCardSourceControllerEffect(1), filter)); } private ThopterSpyNetwork(final ThopterSpyNetwork card) { @@ -78,51 +79,4 @@ class ThopterSpyNetworkUpkeepTriggeredAbility extends TriggeredAbilityImpl { public String getRule() { return "At the beginning of your upkeep, if you control an artifact, create a 1/1 colorless Thopter artifact creature token with flying."; } -} - -class ThopterSpyNetworkDamageTriggeredAbility extends TriggeredAbilityImpl { - - private final List damagedPlayerIds = new ArrayList<>(); - - ThopterSpyNetworkDamageTriggeredAbility() { - super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), false); - } - - private ThopterSpyNetworkDamageTriggeredAbility(final ThopterSpyNetworkDamageTriggeredAbility ability) { - super(ability); - } - - @Override - public ThopterSpyNetworkDamageTriggeredAbility copy() { - return new ThopterSpyNetworkDamageTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER - || event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_POST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.DAMAGED_PLAYER) { - if (((DamagedPlayerEvent) event).isCombatDamage()) { - Permanent creature = game.getPermanent(event.getSourceId()); - if (creature != null && creature.isControlledBy(controllerId) - && creature.isArtifact(game) && !damagedPlayerIds.contains(event.getTargetId())) { - damagedPlayerIds.add(event.getTargetId()); - return true; - } - } - } - if (event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_POST) { - damagedPlayerIds.clear(); - } - return false; - } - - @Override - public String getRule() { - return "Whenever one or more artifact creatures you control deal combat damage to a player, draw a card."; - } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/ThunderbladeCharge.java b/Mage.Sets/src/mage/cards/t/ThunderbladeCharge.java index 29e05a79427..54f23daae81 100644 --- a/Mage.Sets/src/mage/cards/t/ThunderbladeCharge.java +++ b/Mage.Sets/src/mage/cards/t/ThunderbladeCharge.java @@ -13,7 +13,9 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.SetTargetPointer; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetAnyTarget; @@ -34,10 +36,12 @@ public final class ThunderbladeCharge extends CardImpl { // Whenever one or more creatures you control deal combat damage to a player, // if Thunderblade Charge is in your graveyard, you may pay {2}{R}{R}{R}. // If you do, you may cast it without paying its mana cost. - this.addAbility(new DealCombatDamageControlledTriggeredAbility(Zone.GRAVEYARD, - new DoIfCostPaid(new ThunderbladeChargeCastEffect(), new ManaCostsImpl<>("{2}{R}{R}{R}")) - .setText("if {this} is in your graveyard, you may pay {2}{R}{R}{R}. " - + "If you do, you may cast it without paying its mana cost"))); + this.addAbility(new DealCombatDamageControlledTriggeredAbility( + Zone.GRAVEYARD, + new DoIfCostPaid(new ThunderbladeChargeCastEffect(), new ManaCostsImpl<>("{2}{R}{R}{R}")) + .setText("if {this} is in your graveyard, you may pay {2}{R}{R}{R}. If you do, you may cast it without paying its mana cost"), + StaticFilters.FILTER_PERMANENT_CREATURES, SetTargetPointer.NONE, false) + ); } private ThunderbladeCharge(final ThunderbladeCharge card) { diff --git a/Mage/src/main/java/mage/abilities/common/DealCombatDamageControlledTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DealCombatDamageControlledTriggeredAbility.java index ef7f262b49f..fc9fa040414 100644 --- a/Mage/src/main/java/mage/abilities/common/DealCombatDamageControlledTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DealCombatDamageControlledTriggeredAbility.java @@ -2,55 +2,50 @@ package mage.abilities.common; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; +import mage.constants.SetTargetPointer; import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; +import mage.game.events.DamagedBatchEvent; +import mage.game.events.DamagedEvent; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; +import java.util.List; +import java.util.stream.Collectors; /** * @author LevelX2 */ public class DealCombatDamageControlledTriggeredAbility extends TriggeredAbilityImpl { - private final Set damagedPlayerIds = new HashSet<>(); - private final boolean setTargetPointer; - private final boolean onlyOpponents; + private final SetTargetPointer setTargetPointer; + private final FilterCreaturePermanent filter; public DealCombatDamageControlledTriggeredAbility(Effect effect) { - this(Zone.BATTLEFIELD, effect); + this(effect, SetTargetPointer.NONE); } - public DealCombatDamageControlledTriggeredAbility(Zone zone, Effect effect) { - this(zone, effect, false); + public DealCombatDamageControlledTriggeredAbility(Effect effect, FilterCreaturePermanent filter) { + this(Zone.BATTLEFIELD, effect, filter, SetTargetPointer.NONE, false); } - public DealCombatDamageControlledTriggeredAbility(Zone zone, Effect effect, boolean setTargetPointer) { - this(zone, effect, setTargetPointer, false); + public DealCombatDamageControlledTriggeredAbility(Effect effect, SetTargetPointer setTargetPointer) { + this(Zone.BATTLEFIELD, effect, StaticFilters.FILTER_PERMANENT_CREATURES, setTargetPointer, false); } - public DealCombatDamageControlledTriggeredAbility(Zone zone, Effect effect, boolean setTargetPointer, boolean onlyOpponents) { - this(zone, effect, setTargetPointer, onlyOpponents, false); - } - - public DealCombatDamageControlledTriggeredAbility(Zone zone, Effect effect, boolean setTargetPointer, boolean onlyOpponents, boolean optional) { + public DealCombatDamageControlledTriggeredAbility(Zone zone, Effect effect, FilterCreaturePermanent filter, SetTargetPointer setTargetPointer, boolean optional) { super(zone, effect, optional); this.setTargetPointer = setTargetPointer; - this.onlyOpponents = onlyOpponents; - setTriggerPhrase("Whenever one or more creatures you control deal combat damage to " - + (onlyOpponents ? "an opponent" : "a player") + ", "); + this.filter = filter; + setTriggerPhrase("Whenever one or more " + filter.getMessage() + " you control deal combat damage to a player, "); } protected DealCombatDamageControlledTriggeredAbility(final DealCombatDamageControlledTriggeredAbility ability) { super(ability); this.setTargetPointer = ability.setTargetPointer; - this.onlyOpponents = ability.onlyOpponents; + this.filter = ability.filter; } @Override @@ -60,34 +55,36 @@ public class DealCombatDamageControlledTriggeredAbility extends TriggeredAbility @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER - || event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_PRIORITY - || event.getType() == GameEvent.EventType.ZONE_CHANGE; + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER_BATCH_ONE_PLAYER; } @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_PRIORITY || - (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(getSourceId()))) { - damagedPlayerIds.clear(); + List events = ((DamagedBatchEvent) event).getEvents().stream() + .filter(DamagedEvent::isCombatDamage) + .filter(e -> { + Permanent permanent = game.getPermanentOrLKIBattlefield(e.getSourceId()); + return permanent != null + && filter.match(permanent, game) + && permanent.isControlledBy(this.getControllerId()); + }) + .collect(Collectors.toList()); + + if (events.isEmpty()) { return false; } - if (event.getType() != EventType.DAMAGED_PLAYER) { - return false; - } - DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; - Permanent p = game.getPermanent(event.getSourceId()); - if (!damageEvent.isCombatDamage() - || p == null - || !p.isControlledBy(this.getControllerId()) - || damagedPlayerIds.contains(event.getPlayerId()) - || (onlyOpponents && !game.getOpponents(getControllerId()).contains(event.getPlayerId()))) { - return false; - } - damagedPlayerIds.add(event.getPlayerId()); - if (setTargetPointer) { - this.getEffects().setTargetPointer(new FixedTarget(event.getPlayerId())); + + this.getEffects().setValue("damage", events.stream().mapToInt(DamagedEvent::getAmount).sum()); + switch (setTargetPointer) { + case PLAYER: + this.getEffects().setTargetPointer(new FixedTarget(event.getPlayerId())); + break; + case NONE: + break; + default: + throw new IllegalArgumentException("Invalid SetTargetPointer option"); } + return true; } -} +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/game/command/emblems/LolthSpiderQueenEmblem.java b/Mage/src/main/java/mage/game/command/emblems/LolthSpiderQueenEmblem.java index 91f0704df40..50c625e009d 100644 --- a/Mage/src/main/java/mage/game/command/emblems/LolthSpiderQueenEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/LolthSpiderQueenEmblem.java @@ -7,7 +7,9 @@ import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; +import mage.constants.SetTargetPointer; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.command.Emblem; import mage.players.Player; @@ -25,7 +27,7 @@ public final class LolthSpiderQueenEmblem extends Emblem { super("Emblem Lolth"); this.getAbilities().add(new ConditionalInterveningIfTriggeredAbility( new DealCombatDamageControlledTriggeredAbility( - Zone.COMMAND, new LolthSpiderQueenEmblemEffect(), true, true + Zone.COMMAND, new LolthSpiderQueenEmblemEffect(), StaticFilters.FILTER_PERMANENT_CREATURES, SetTargetPointer.PLAYER, false ), LolthSpiderQueenEmblemCondition.instance, "Whenever an opponent " + "is dealt combat damage by one or more creatures you control, " + "if that player lost less than 8 life this turn, they lose life equal to the difference."