From f3355d529ac0f1ba64f4aae056abcb90f6ba0284 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Tue, 21 Dec 2021 16:34:18 +0000 Subject: [PATCH] Ignore hexproof shroud --- .../game/ability/effects/PumpEffect.java | 2 - .../src/main/java/forge/game/card/Card.java | 9 +- .../main/java/forge/game/player/Player.java | 9 +- .../game/staticability/StaticAbility.java | 46 --------- .../StaticAbilityCantTarget.java | 94 ++++++++++--------- .../StaticAbilityIgnoreHexproofShroud.java | 50 ++++++++++ forge-gui/res/cardsfolder/a/autumn_willow.txt | 3 +- .../res/cardsfolder/d/detection_tower.txt | 3 +- .../res/cardsfolder/g/glaring_spotlight.txt | 3 +- .../cardsfolder/k/kaya_bane_of_the_dead.txt | 2 +- 10 files changed, 110 insertions(+), 111 deletions(-) create mode 100644 forge-game/src/main/java/forge/game/staticability/StaticAbilityIgnoreHexproofShroud.java diff --git a/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java index 5e8d30f477a..d6906c871b2 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java @@ -263,8 +263,6 @@ public class PumpEffect extends SpellAbilityEffect { String replaced = ""; if (defined.equals("ChosenType")) { replaced = host.getChosenType(); - } else if (defined.equals("CardUIDSource")) { - replaced = "CardUID_" + host.getId(); } else if (defined.equals("ActivatorName")) { replaced = sa.getActivatingPlayer().getName(); } else if (defined.equals("ChosenPlayer")) { diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 443be2eeae7..26f39d4db91 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -57,6 +57,7 @@ import forge.game.staticability.StaticAbility; import forge.game.staticability.StaticAbilityCantAttackBlock; import forge.game.staticability.StaticAbilityCantPutCounter; import forge.game.staticability.StaticAbilityCantSacrifice; +import forge.game.staticability.StaticAbilityCantTarget; import forge.game.staticability.StaticAbilityCantTransform; import forge.game.trigger.Trigger; import forge.game.trigger.TriggerType; @@ -5960,12 +5961,8 @@ public class Card extends GameEntity implements Comparable, IHasSVars { } // CantTarget static abilities - for (final Card ca : getGame().getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) { - for (final StaticAbility stAb : ca.getStaticAbilities()) { - if (stAb.applyAbility("CantTarget", this, sa)) { - return false; - } - } + if (StaticAbilityCantTarget.cantTarget(this, sa)) { + return false; } // keywords don't work outside battlefield diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index e51dccd6ab2..71b14c8b153 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -108,6 +108,7 @@ import forge.game.staticability.StaticAbilityCantDiscard; import forge.game.staticability.StaticAbilityCantDraw; import forge.game.staticability.StaticAbilityCantGainLosePayLife; import forge.game.staticability.StaticAbilityCantPutCounter; +import forge.game.staticability.StaticAbilityCantTarget; import forge.game.trigger.Trigger; import forge.game.trigger.TriggerHandler; import forge.game.trigger.TriggerType; @@ -1139,12 +1140,8 @@ public class Player extends GameEntity implements Comparable { } // CantTarget static abilities - for (final Card ca : getGame().getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) { - for (final StaticAbility stAb : ca.getStaticAbilities()) { - if (stAb.applyAbility("CantTarget", this, sa)) { - return false; - } - } + if (StaticAbilityCantTarget.cantTarget(this, sa)) { + return false; } return !hasProtectionFrom(sa.getHostCard()); diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java index 78b2f9ce273..9e024edc5e3 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java @@ -41,7 +41,6 @@ import forge.game.cost.Cost; import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; import forge.game.player.Player; -import forge.game.spellability.SpellAbility; import forge.game.zone.Zone; import forge.game.zone.ZoneType; import forge.util.CardTranslation; @@ -284,51 +283,6 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone return getParam("Mode").equals("Continuous") && layers.contains(layer) && !isSuppressed() && checkConditions() && (previousRun || getHostCard().getStaticAbilities().contains(this)); } - /** - * Apply ability. - * - * @param mode - * the mode - * @param card - * the card - * @param spellAbility - * the ability - * @return true, if successful - */ - public final boolean applyAbility(final String mode, final Card card, final SpellAbility spellAbility) { - // don't apply the ability if it hasn't got the right mode - if (!getParam("Mode").equals(mode)) { - return false; - } - - if (this.isSuppressed() || !this.checkConditions()) { - return false; - } - - if (mode.equals("CantTarget")) { - return StaticAbilityCantTarget.applyCantTargetAbility(this, card, spellAbility); - } - - return false; - } - - public final boolean applyAbility(final String mode, final Player player, final SpellAbility spellAbility) { - // don't apply the ability if it hasn't got the right mode - if (!getParam("Mode").equals(mode)) { - return false; - } - - if (this.isSuppressed() || !this.checkConditions()) { - return false; - } - - if (mode.equals("CantTarget")) { - return StaticAbilityCantTarget.applyCantTargetAbility(this, player, spellAbility); - } - - return false; - } - public final boolean applyAbility(final String mode, final Card card, final boolean isCombat) { // don't apply the ability if it hasn't got the right mode if (!getParam("Mode").equals(mode)) { diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantTarget.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantTarget.java index fc0aa270f94..159bd40f8e8 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantTarget.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantTarget.java @@ -17,8 +17,10 @@ */ package forge.game.staticability; +import forge.game.Game; +import forge.game.GameEntity; import forge.game.card.Card; -import forge.game.keyword.KeywordInterface; +import forge.game.keyword.Keyword; import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; @@ -28,6 +30,40 @@ import forge.game.zone.ZoneType; */ public class StaticAbilityCantTarget { + static String MODE = "CantTarget"; + + public static boolean cantTarget(final Card card, final SpellAbility spellAbility) { + final Game game = card.getGame(); + for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) { + for (final StaticAbility stAb : ca.getStaticAbilities()) { + if (!stAb.getParam("Mode").equals(MODE) || stAb.isSuppressed() || !stAb.checkConditions()) { + continue; + } + + if (applyCantTargetAbility(stAb, card, spellAbility)) { + return true; + } + } + } + return false; + } + + public static boolean cantTarget(final Player player, final SpellAbility spellAbility) { + final Game game = player.getGame(); + for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) { + for (final StaticAbility stAb : ca.getStaticAbilities()) { + if (!stAb.getParam("Mode").equals(MODE) || stAb.isSuppressed() || !stAb.checkConditions()) { + continue; + } + + if (applyCantTargetAbility(stAb, player, spellAbility)) { + return true; + } + } + } + return false; + } + /** * Apply can't target ability. * @@ -41,8 +77,6 @@ public class StaticAbilityCantTarget { */ public static boolean applyCantTargetAbility(final StaticAbility stAb, final Card card, final SpellAbility spellAbility) { - final Card source = spellAbility.getHostCard(); - final Player activator = spellAbility.getActivatingPlayer(); if (stAb.hasParam("ValidPlayer")) { return false; @@ -70,36 +104,10 @@ public class StaticAbilityCantTarget { return false; } - if (stAb.hasParam("Hexproof") && (activator != null)) { - for (KeywordInterface kw : activator.getKeywords()) { - String k = kw.getOriginal(); - if (k.startsWith("IgnoreHexproof")) { - String[] m = k.split(":"); - if (card.isValid(m[1].split(","), activator, source, null)) { - return false; - } - } - } - } - if (stAb.hasParam("Shroud") && (activator != null)) { - for (KeywordInterface kw : activator.getKeywords()) { - String k = kw.getOriginal(); - if (k.startsWith("IgnoreShroud")) { - String[] m = k.split(":"); - if (card.isValid(m[1].split(","), activator, source, null)) { - return false; - } - } - } - } - - return common(stAb, spellAbility); + return common(stAb, card, spellAbility); } - public static boolean applyCantTargetAbility(final StaticAbility stAb, final Player player, - final SpellAbility spellAbility) { - final Card source = spellAbility.getHostCard(); - final Player activator = spellAbility.getActivatingPlayer(); + public static boolean applyCantTargetAbility(final StaticAbility stAb, final Player player, final SpellAbility spellAbility) { if (stAb.hasParam("ValidCard") || stAb.hasParam("AffectedZone")) { return false; @@ -109,25 +117,21 @@ public class StaticAbilityCantTarget { return false; } - if (stAb.hasParam("Hexproof") && (activator != null)) { - for (KeywordInterface kw : activator.getKeywords()) { - String k = kw.getOriginal(); - if (k.startsWith("IgnoreHexproof")) { - String[] m = k.split(":"); - if (player.isValid(m[1].split(","), activator, source, null)) { - return false; - } - } - } - } - - return common(stAb, spellAbility); + return common(stAb, player, spellAbility); } - protected static boolean common(final StaticAbility stAb, final SpellAbility spellAbility) { + protected static boolean common(final StaticAbility stAb, GameEntity entity, final SpellAbility spellAbility) { final Card source = spellAbility.getHostCard(); final Player activator = spellAbility.getActivatingPlayer(); + if (stAb.hasParam("Hexproof") && StaticAbilityIgnoreHexproofShroud.ignore(entity, spellAbility, Keyword.HEXPROOF)) { + return false; + } + + if (stAb.hasParam("Shroud") && StaticAbilityIgnoreHexproofShroud.ignore(entity, spellAbility, Keyword.SHROUD)) { + return false; + } + if (!stAb.matchesValidParam("ValidSA", spellAbility)) { return false; } diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityIgnoreHexproofShroud.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityIgnoreHexproofShroud.java new file mode 100644 index 00000000000..6a28d3df47d --- /dev/null +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityIgnoreHexproofShroud.java @@ -0,0 +1,50 @@ +package forge.game.staticability; + +import forge.game.Game; +import forge.game.GameEntity; +import forge.game.card.Card; +import forge.game.keyword.Keyword; +import forge.game.player.Player; +import forge.game.spellability.SpellAbility; +import forge.game.zone.ZoneType; + +public class StaticAbilityIgnoreHexproofShroud { + + static String HEXPROOF_MODE = "IgnoreHexproof"; + static String SHROUD_MODE = "IgnoreShroud"; + + static public boolean ignore(GameEntity entity, final SpellAbility spellAbility, Keyword keyword) { + final Game game = entity.getGame(); + for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) { + for (final StaticAbility stAb : ca.getStaticAbilities()) { + if (stAb.isSuppressed() || !stAb.checkConditions()) { + continue; + } + if (keyword.equals(Keyword.HEXPROOF) && !stAb.getParam("Mode").equals(HEXPROOF_MODE)) { + continue; + } + if (keyword.equals(Keyword.SHROUD) && !stAb.getParam("Mode").equals(SHROUD_MODE)) { + continue; + } + if (commonAbility(stAb, entity, spellAbility)) { + return true; + } + } + } + return false; + } + + static protected boolean commonAbility(StaticAbility stAb, GameEntity entity, final SpellAbility spellAbility) { + final Player activator = spellAbility.getActivatingPlayer(); + + if (!stAb.matchesValidParam("Activator", activator)) { + return false; + } + + if (!stAb.matchesValidParam("ValidEntity", entity)) { + return false; + } + + return true; + } +} diff --git a/forge-gui/res/cardsfolder/a/autumn_willow.txt b/forge-gui/res/cardsfolder/a/autumn_willow.txt index 13682aabdb2..4792cc01e0e 100644 --- a/forge-gui/res/cardsfolder/a/autumn_willow.txt +++ b/forge-gui/res/cardsfolder/a/autumn_willow.txt @@ -3,6 +3,7 @@ ManaCost:4 G G Types:Legendary Creature Avatar PT:4/4 K:Shroud -A:AB$ Pump | Cost$ G | ValidTgts$ Player | Defined$ Targeted | TgtPrompt$ Select target player to be able to target Autumn Willow | KW$ IgnoreShroud:Card.CardUIDSource | DefinedKW$ CardUIDSource | Duration$ UntilHostLeavesPlayOrEOT | StackDescription$ Until end of turn, {p:Targeted} can target CARDNAME as though it didn't have shroud. | SpellDescription$ Until end of turn, Autumn Willow can be the target of spells and abilities controlled by target player as though it didn't have shroud. +A:AB$ Effect | Cost$ G | StaticAbilities$ STLoseAB | RememberObjects$ TargetedPlayer | Duration$ UntilHostLeavesPlayOrEOT | ValidTgts$ Player | TgtPrompt$ Select target player to be able to target CARDNAME | StackDescription$ Until end of turn, {p:Targeted} can target CARDNAME as though it didn't have shroud. | SpellDescription$ Until end of turn, Autumn Willow can be the target of spells and abilities controlled by target player as though it didn't have shroud. +SVar:STLoseAB:Mode$ IgnoreShroud | Activator$ Player.IsRemembered | ValidEntity$ Card.EffectSource | Description$ Until end of turn, EFFECTSOURCE can be the target of spells and abilities controlled by target player as though it didn't have shroud. AI:RemoveDeck:All Oracle:Shroud (This creature can't be the target of spells or abilities.)\n{G}: Until end of turn, Autumn Willow can be the target of spells and abilities controlled by target player as though it didn't have shroud. diff --git a/forge-gui/res/cardsfolder/d/detection_tower.txt b/forge-gui/res/cardsfolder/d/detection_tower.txt index 6ab61cc86d5..e9b95488841 100644 --- a/forge-gui/res/cardsfolder/d/detection_tower.txt +++ b/forge-gui/res/cardsfolder/d/detection_tower.txt @@ -3,7 +3,6 @@ ManaCost:no cost Types:Land A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}. A:AB$ Effect | Cost$ 1 T | StaticAbilities$ STLoseAB | SpellDescription$ Until end of turn, your opponents and creatures your opponents control with hexproof can be the targets of spells and abilities you control as though they didn't have hexproof. -SVar:STLoseAB:Mode$ Continuous | EffectZone$ Command | Affected$ You | AddKeyword$ IgnoreHexproof:Opponent,Creature.OppCtrl | Description$ Your opponents and creatures your opponents control with hexproof can be the targets of spells and abilities you control as though they didn't have hexproof. +SVar:STLoseAB:Mode$ IgnoreHexproof | Activator$ You | ValidEntity$ Opponent,Creature.OppCtrl | Description$ Your opponents and creatures your opponents control with hexproof can be the targets of spells and abilities you control as though they didn't have hexproof. AI:RemoveDeck:All -SVar:Picture:http://www.wizards.com/global/images/magic/general/detection_tower.jpg Oracle:{T}: Add {C}.\n{1}, {T}: Until end of turn, your opponents and creatures your opponents control with hexproof can be the targets of spells and abilities you control as though they didn't have hexproof. diff --git a/forge-gui/res/cardsfolder/g/glaring_spotlight.txt b/forge-gui/res/cardsfolder/g/glaring_spotlight.txt index a45d751b09e..c95bcc9b89c 100644 --- a/forge-gui/res/cardsfolder/g/glaring_spotlight.txt +++ b/forge-gui/res/cardsfolder/g/glaring_spotlight.txt @@ -1,9 +1,8 @@ Name:Glaring Spotlight ManaCost:1 Types:Artifact -S:Mode$ Continuous | Affected$ You | AddKeyword$ IgnoreHexproof:Creature.OppCtrl | Description$ Creatures your opponents control with hexproof can be the targets of spells and abilities you control as though they didn't have hexproof. +S:Mode$ IgnoreHexproof | Activator$ You | ValidEntity$ Creature.OppCtrl | Description$ Creatures your opponents control with hexproof can be the targets of spells and abilities you control as though they didn't have hexproof. A:AB$ PumpAll | Cost$ 3 Sac<1/CARDNAME> | ValidCards$ Creature.YouCtrl | KW$ Hexproof | SubAbility$ GSEffect | SpellDescription$ Creatures you control gain hexproof until end of turn and can't be blocked this turn. SVar:GSEffect:DB$ Effect | Name$ Glaring Spotlight Effect | StaticAbilities$ KWPump SVar:KWPump:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Creature.YouCtrl | AddHiddenKeyword$ Unblockable | Description$ Creatures you control can't be blocked this turn. -SVar:Picture:http://www.wizards.com/global/images/magic/general/glaring_spotlight.jpg Oracle:Creatures your opponents control with hexproof can be the targets of spells and abilities you control as though they didn't have hexproof.\n{3}, Sacrifice Glaring Spotlight: Creatures you control gain hexproof until end of turn and can't be blocked this turn. diff --git a/forge-gui/res/cardsfolder/k/kaya_bane_of_the_dead.txt b/forge-gui/res/cardsfolder/k/kaya_bane_of_the_dead.txt index 2896bdb4bd1..09f2180681d 100644 --- a/forge-gui/res/cardsfolder/k/kaya_bane_of_the_dead.txt +++ b/forge-gui/res/cardsfolder/k/kaya_bane_of_the_dead.txt @@ -2,7 +2,7 @@ Name:Kaya, Bane of the Dead ManaCost:3 W/B W/B W/B Types:Legendary Planeswalker Kaya Loyalty:7 -S:Mode$ Continuous | Affected$ You | AddKeyword$ IgnoreHexproof:Permanent.OppCtrl,Opponent | Description$ Your opponents and permanents your opponents control with hexproof can be the targets of spells and abilities you control as though they didn't have hexproof. +S:Mode$ IgnoreHexproof | Activator$ You | ValidEntity$ Permanent.OppCtrl,Opponent | Description$ Your opponents and permanents your opponents control with hexproof can be the targets of spells and abilities you control as though they didn't have hexproof. SVar:PlayMain1:TRUE A:AB$ ChangeZone | Cost$ SubCounter<3/LOYALTY> | Planeswalker$ true | ValidTgts$ Creature | TgtPrompt$ Select target creature | Origin$ Battlefield | Destination$ Exile | SpellDescription$ Exile target creature. Oracle:Your opponents and permanents your opponents control with hexproof can be the targets of spells and abilities you control as though they didn't have hexproof.\n[−3]: Exile target creature.