Merge branch 'ignoreHexproofShroud' into 'master'

Ignore hexproof shroud

See merge request core-developers/forge!5964
This commit is contained in:
Michael Kamensky
2021-12-21 16:34:19 +00:00
10 changed files with 110 additions and 111 deletions

View File

@@ -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")) {

View File

@@ -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<Card>, 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

View File

@@ -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<Player> {
}
// 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());

View File

@@ -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)) {

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.