diff --git a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java index d2ae1de2379..cd99a5a6d94 100644 --- a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java +++ b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java @@ -228,7 +228,7 @@ public class GameCopier { CardFactory.copyCopiableCharacteristics(c, result); return result; } - if (USE_FROM_PAPER_CARD && !c.isEmblem()) { + if (USE_FROM_PAPER_CARD && !c.isEmblem() && c.getPaperCard() != null) { Card newCard = Card.fromPaperCard(c.getPaperCard(), newOwner); newCard.setCommander(c.isCommander()); return newCard; 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 e43f7876b5d..75d8693b8f0 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 @@ -120,7 +120,10 @@ public class PumpEffect extends SpellAbilityEffect { && !(host.isInPlay() || host.isInZone(ZoneType.Stack))) { return; } - p.addChangedKeywords(keywords, ImmutableList.of(), timestamp); + + if (!keywords.isEmpty()) { + p.addChangedKeywords(keywords, ImmutableList.of(), timestamp); + } if (!sa.hasParam("Permanent")) { // If not Permanent, remove Pumped at EOT @@ -129,12 +132,7 @@ public class PumpEffect extends SpellAbilityEffect { @Override public void run() { - - if (keywords.size() > 0) { - for (int i = 0; i < keywords.size(); i++) { - p.removeKeyword(keywords.get(i)); - } - } + p.removeChangedKeywords(timestamp); } }; addUntilCommand(sa, untilEOT); 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 b4e02f993cb..e7fac44ec75 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -5618,34 +5618,7 @@ public class Card extends GameEntity implements Comparable { } final Card source = sa.getHostCard(); - final MutableBoolean result = new MutableBoolean(true); - visitKeywords(currentState, new Visitor() { - @Override - public boolean visit(KeywordInterface kw) { - switch (kw.getOriginal()) { - case "Shroud": - StringBuilder sb = new StringBuilder(); - sb.append("Can target CardUID_").append(getId()); - sb.append(" with spells and abilities as though it didn't have shroud."); - if (sa.getActivatingPlayer() == null) { - System.err.println("Unexpected behavior: SA activator was null when trying to determine if the activating player could target a card with Shroud. SA host card = " + source + ", SA = " + sa); - result.setFalse(); // FIXME: maybe this should check by SA host card controller at this point instead? - } else if (!sa.getActivatingPlayer().hasKeyword(sb.toString())) { - result.setFalse(); - } - break; - case "CARDNAME can't be the target of spells.": - if (sa.isSpell()) { - result.setFalse(); - } - break; - } - return result.isTrue(); - } - }); - if (result.isFalse()) { - return false; - } + if (sa.isSpell()) { for(KeywordInterface inst : source.getKeywords()) { String kw = inst.getOriginal(); diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java index 46233143730..d5ffd39750c 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -4501,7 +4501,9 @@ public class CardFactoryUtil { effect = "Mode$ CantTarget | Hexproof$ True | ValidCard$ Card.Self | Secondary$ True" + sbValid.toString() + " | Activator$ Opponent | Description$ " + sbDesc.toString() + " (" + inst.getReminderText() + ")"; - + } else if (keyword.equals("Shroud")) { + effect = "Mode$ CantTarget | Shroud$ True | ValidCard$ Card.Self | Secondary$ True" + + " | Description$ Shroud (" + inst.getReminderText() + ")"; } else if (keyword.startsWith("Strive")) { final String[] k = keyword.split(":"); final String manacost = k[1]; diff --git a/forge-game/src/main/java/forge/game/keyword/KeywordInstance.java b/forge-game/src/main/java/forge/game/keyword/KeywordInstance.java index 6e7adb840fb..0ef5b3ffcd7 100644 --- a/forge-game/src/main/java/forge/game/keyword/KeywordInstance.java +++ b/forge-game/src/main/java/forge/game/keyword/KeywordInstance.java @@ -9,6 +9,8 @@ import com.google.common.collect.Lists; import forge.game.card.Card; import forge.game.card.CardFactoryUtil; +import forge.game.player.Player; +import forge.game.player.PlayerFactoryUtil; import forge.game.replacement.ReplacementEffect; import forge.game.spellability.SpellAbility; import forge.game.staticability.StaticAbility; @@ -82,7 +84,7 @@ public abstract class KeywordInstance> implements K public final void createTraits(final Card host, final boolean intrinsic) { createTraits(host, intrinsic, false); } - + /* * (non-Javadoc) * @see forge.game.keyword.KeywordInterface#createTraits(forge.game.card.Card, boolean, boolean) @@ -125,6 +127,53 @@ public abstract class KeywordInstance> implements K } } + /* (non-Javadoc) + * @see forge.game.keyword.KeywordInterface#createTraits(forge.game.player.Player) + */ + @Override + public void createTraits(Player player) { + createTraits(player, false); + } + /* (non-Javadoc) + * @see forge.game.keyword.KeywordInterface#createTraits(forge.game.player.Player, boolean) + */ + @Override + public void createTraits(Player player, boolean clear) { + if (clear) { + triggers.clear(); + replacements.clear(); + abilities.clear(); + staticAbilities.clear(); + } + try { + String msg = "KeywordInstance:createTraits: make Traits for Keyword"; + Sentry.getContext().recordBreadcrumb( + new BreadcrumbBuilder().setMessage(msg) + .withData("Player", player.getName()).withData("Keyword", this.original).build() + ); + + // add Extra for debugging + Sentry.getContext().addExtra("Player", player); + Sentry.getContext().addExtra("Keyword", this.original); + + PlayerFactoryUtil.addTriggerAbility(this, player); + PlayerFactoryUtil.addReplacementEffect(this, player); + PlayerFactoryUtil.addSpellAbility(this, player); + PlayerFactoryUtil.addStaticAbility(this, player); + } catch (Exception e) { + String msg = "KeywordInstance:createTraits: failed Traits for Keyword"; + Sentry.getContext().recordBreadcrumb( + new BreadcrumbBuilder().setMessage(msg) + .withData("Player", player.getName()).withData("Keyword", this.original).build() + ); + //rethrow + throw new RuntimeException("Error in Keyword " + this.original + " for player " + player.getName(), e); + } finally { + // remove added extra + Sentry.getContext().removeExtra("Player"); + Sentry.getContext().removeExtra("Keyword"); + } + } /* * (non-Javadoc) * @see forge.game.keyword.KeywordInterface#addTrigger(forge.game.trigger.Trigger) diff --git a/forge-game/src/main/java/forge/game/keyword/KeywordInterface.java b/forge-game/src/main/java/forge/game/keyword/KeywordInterface.java index d8b5f152605..2832cdd2ee4 100644 --- a/forge-game/src/main/java/forge/game/keyword/KeywordInterface.java +++ b/forge-game/src/main/java/forge/game/keyword/KeywordInterface.java @@ -3,6 +3,7 @@ package forge.game.keyword; import java.util.Collection; import forge.game.card.Card; +import forge.game.player.Player; import forge.game.replacement.ReplacementEffect; import forge.game.spellability.SpellAbility; import forge.game.staticability.StaticAbility; @@ -24,6 +25,9 @@ public interface KeywordInterface extends Cloneable { void createTraits(final Card host, final boolean intrinsic); void createTraits(final Card host, final boolean intrinsic, final boolean clear); + void createTraits(final Player player); + void createTraits(final Player player, final boolean clear); + void addTrigger(final Trigger trg); void addReplacement(final ReplacementEffect trg); diff --git a/forge-game/src/main/java/forge/game/keyword/KeywordsChange.java b/forge-game/src/main/java/forge/game/keyword/KeywordsChange.java index 1f87bc4762f..73e1c1aa272 100644 --- a/forge-game/src/main/java/forge/game/keyword/KeywordsChange.java +++ b/forge-game/src/main/java/forge/game/keyword/KeywordsChange.java @@ -23,6 +23,11 @@ import java.util.List; import com.google.common.collect.Lists; import forge.game.card.Card; +import forge.game.player.Player; +import forge.game.replacement.ReplacementEffect; +import forge.game.spellability.SpellAbility; +import forge.game.staticability.StaticAbility; +import forge.game.trigger.Trigger; /** *

@@ -131,7 +136,13 @@ public class KeywordsChange implements Cloneable { inst.createTraits(host, false, true); } } - + + public final void addKeywordsToPlayer(final Player player) { + for (KeywordInterface inst : keywords.getValues()) { + inst.createTraits(player, true); + } + } + public final boolean removeKeywordfromAdd(final String keyword) { return keywords.remove(keyword); } @@ -201,6 +212,47 @@ public class KeywordsChange implements Cloneable { } } + /** + * @return the triggers + */ + public Collection getTriggers() { + List result = Lists.newArrayList(); + for (KeywordInterface k : this.keywords.getValues()) { + result.addAll(k.getTriggers()); + } + return result; + } + /** + * @return the replacements + */ + public Collection getReplacements() { + List result = Lists.newArrayList(); + for (KeywordInterface k : this.keywords.getValues()) { + result.addAll(k.getReplacements()); + } + return result; + } + /** + * @return the abilities + */ + public Collection getAbilities() { + List result = Lists.newArrayList(); + for (KeywordInterface k : this.keywords.getValues()) { + result.addAll(k.getAbilities()); + } + return result; + } + /** + * @return the staticAbilities + */ + public Collection getStaticAbilities() { + List result = Lists.newArrayList(); + for (KeywordInterface k : this.keywords.getValues()) { + result.addAll(k.getStaticAbilities()); + } + return result; + } + /* (non-Javadoc) * @see java.lang.Object#toString() */ 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 76d0d56c21e..6d5ac51478c 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -20,6 +20,8 @@ package forge.game.player; import com.google.common.base.Function; import com.google.common.base.Predicates; import com.google.common.collect.*; + +import forge.ImageKeys; import forge.LobbyPlayer; import forge.card.MagicColor; import forge.game.*; @@ -41,7 +43,6 @@ import forge.game.phase.PhaseType; import forge.game.replacement.ReplacementHandler; import forge.game.replacement.ReplacementResult; import forge.game.replacement.ReplacementType; -import forge.game.spellability.AbilityActivated; import forge.game.spellability.SpellAbility; import forge.game.staticability.StaticAbility; import forge.game.trigger.Trigger; @@ -155,6 +156,7 @@ public class Player extends GameEntity implements Comparable { private Card monarchEffect = null; private Card blessingEffect = null; + private Card keywordEffect = null; private final AchievementTracker achievementTracker = new AchievementTracker(); private final PlayerView view; @@ -1025,23 +1027,25 @@ public class Player extends GameEntity implements Comparable { public final void addChangedKeywords(final List addKeywords, final List removeKeywords, final Long timestamp) { // if the key already exists - merge entries + KeywordsChange cks = null; if (changedKeywords.containsKey(timestamp)) { - final KeywordsChange cks = changedKeywords.get(timestamp); + getKeywordCard().removeChangedCardTraits(timestamp); - changedKeywords.put(timestamp, cks.merge(addKeywords, removeKeywords, - cks.isRemoveAllKeywords(), cks.isRemoveIntrinsicKeywords())); - updateKeywords(); - return; + cks = changedKeywords.get(timestamp).merge(addKeywords, removeKeywords, false, false); + } else { + cks = new KeywordsChange(addKeywords, removeKeywords, false, false); } - - changedKeywords.put(timestamp, new KeywordsChange(addKeywords, removeKeywords, false, false)); + cks.addKeywordsToPlayer(this); + getKeywordCard().addChangedCardTraits(cks.getAbilities(), null, cks.getTriggers(), cks.getReplacements(), cks.getStaticAbilities(), false, false, false, timestamp); + changedKeywords.put(timestamp, cks); updateKeywords(); game.fireEvent(new GameEventPlayerStatsChanged(this)); } public final KeywordsChange removeChangedKeywords(final Long timestamp) { - KeywordsChange change = changedKeywords.remove(Long.valueOf(timestamp)); + KeywordsChange change = changedKeywords.remove(timestamp); if (change != null) { + getKeywordCard().removeChangedCardTraits(timestamp); updateKeywords(); game.fireEvent(new GameEventPlayerStatsChanged(this)); } @@ -1100,6 +1104,7 @@ public class Player extends GameEntity implements Comparable { for (final Entry ck : ImmutableList.copyOf(changedKeywords.entrySet())) { if (ck.getValue().isEmpty() && changedKeywords.remove(ck.getKey()) != null) { keywordRemoved = true; + getKeywordCard().removeChangedCardTraits(ck.getKey()); } } @@ -1178,33 +1183,17 @@ public class Player extends GameEntity implements Comparable { @Override public final boolean canBeTargetedBy(final SpellAbility sa) { - if (hasKeyword("Shroud")) { - return false; - } - if (hasKeyword("Hexproof")) { - final Player a = sa.getActivatingPlayer(); - if (isOpponentOf(a)) { - boolean cancelHexproof = false; - for (String k : a.getKeywords()) { - if (k.startsWith("IgnoreHexproof")) { - String[] m = k.split(":"); - if (isValid(m[1].split(","), a, sa.getHostCard(), sa)) { - cancelHexproof = true; - break; - } - } - } - if (!cancelHexproof) { + + // CantTarget static abilities + for (final Card ca : getGame().getCardsIn(ZoneType.listValueOf("Battlefield,Command"))) { + for (final StaticAbility stAb : ca.getStaticAbilities()) { + if (stAb.applyAbility("CantTarget", this, sa)) { return false; } } } - if (hasProtectionFrom(sa.getHostCard())) { - return false; - } - - return (!hasKeyword("You can't be the targets of spells or activated abilities") || (!sa.isSpell() && (!(sa instanceof AbilityActivated)))); + return !hasProtectionFrom(sa.getHostCard()); } @@ -2971,4 +2960,26 @@ public class Player extends GameEntity implements Comparable { || !hasKeyword("Spells and abilities you control can't cause you to search your library."); } + + public Card getKeywordCard() { + if (keywordEffect != null) { + return keywordEffect; + } + + final PlayerZone com = getZone(ZoneType.Command); + + keywordEffect = new Card(game.nextCardId(), null, false, game); + keywordEffect.setImmutable(true); + keywordEffect.setOwner(this); + keywordEffect.setName("Keyword Effects"); + keywordEffect.setImageKey(ImageKeys.HIDDEN_CARD); + keywordEffect.addType("Effect"); + + keywordEffect.updateStateForView(); + + com.add(keywordEffect); + + this.updateZoneForView(com); + return keywordEffect; + } } diff --git a/forge-game/src/main/java/forge/game/player/PlayerFactoryUtil.java b/forge-game/src/main/java/forge/game/player/PlayerFactoryUtil.java new file mode 100644 index 00000000000..0eff22b1711 --- /dev/null +++ b/forge-game/src/main/java/forge/game/player/PlayerFactoryUtil.java @@ -0,0 +1,46 @@ +package forge.game.player; + +import forge.game.card.Card; +import forge.game.keyword.KeywordInterface; +import forge.game.staticability.StaticAbility; + +public class PlayerFactoryUtil { + + public static void addStaticAbility(final KeywordInterface inst, final Player player) { + final Card card = player.getKeywordCard(); + String keyword = inst.getOriginal(); + String effect = null; + if (keyword.startsWith("Hexproof")) { + final StringBuilder sbDesc = new StringBuilder("Hexproof"); + final StringBuilder sbValid = new StringBuilder(); + + if (!keyword.equals("Hexproof")) { + final String[] k = keyword.split(":"); + + sbDesc.append(" from ").append(k[2]); + sbValid.append("| ValidSource$ ").append(k[1]); + } + + effect = "Mode$ CantTarget | Hexproof$ True | ValidPlayer$ Player.You | Secondary$ True " + + sbValid.toString() + " | Activator$ Opponent | EffectZone$ Command | Description$ " + + sbDesc.toString() + " (" + inst.getReminderText() + ")"; + } else if (keyword.equals("Shroud")) { + effect = "Mode$ CantTarget | Shroud$ True | ValidPlayer$ Player.You | Secondary$ True " + + "| EffectZone$ Command | Description$ Shroud (" + inst.getReminderText() + ")"; + } + if (effect != null) { + StaticAbility st = new StaticAbility(effect, card); + st.setIntrinsic(false); + inst.addStaticAbility(st); + } + } + + public static void addTriggerAbility(final KeywordInterface inst, Player player) { + } + + public static void addReplacementEffect(final KeywordInterface inst, Player player) { + } + + public static void addSpellAbility(final KeywordInterface inst, Player player) { + } +} 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 bad27de11c1..5b8cc7018a3 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java @@ -391,6 +391,23 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone 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(String mode, Card card, CounterType type) { // don't apply the ability if it hasn't got the right 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 91ab7dc10bd..e58ede1cd8c 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantTarget.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantTarget.java @@ -6,12 +6,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -22,8 +22,6 @@ import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; -import java.util.Map; - /** * The Class StaticAbilityCantTarget. */ @@ -31,8 +29,8 @@ public class StaticAbilityCantTarget { /** * Apply can't target ability. - * - * @param staticAbility + * + * @param st * the static ability * @param card * the card @@ -40,16 +38,19 @@ public class StaticAbilityCantTarget { * the spell/ability * @return true, if successful */ - public static boolean applyCantTargetAbility(final StaticAbility staticAbility, final Card card, + public static boolean applyCantTargetAbility(final StaticAbility st, final Card card, final SpellAbility spellAbility) { - final Map params = staticAbility.getMapParams(); - final Card hostCard = staticAbility.getHostCard(); + final Card hostCard = st.getHostCard(); final Card source = spellAbility.getHostCard(); final Player activator = spellAbility.getActivatingPlayer(); - if (params.containsKey("AffectedZone")) { + if (st.hasParam("ValidPlayer")) { + return false; + } + + if (st.hasParam("AffectedZone")) { boolean inZone = false; - for (final ZoneType zt : ZoneType.listValueOf(params.get("AffectedZone"))) { + for (final ZoneType zt : ZoneType.listValueOf(st.getParam("AffectedZone"))) { if (card.isInZone(zt)) { inZone = true; break; @@ -65,38 +66,14 @@ public class StaticAbilityCantTarget { } } - if (params.containsKey("ValidSA") - && !spellAbility.isValid(params.get("ValidSA").split(","), hostCard.getController(), hostCard, spellAbility)) { + + if (st.hasParam("ValidCard") + && !card.isValid(st.getParam("ValidCard").split(","), hostCard.getController(), hostCard, null)) { return false; } - if (params.containsKey("ValidCard") - && !card.isValid(params.get("ValidCard").split(","), hostCard.getController(), hostCard, null)) { - return false; - } - if (params.containsKey("ValidSource") - && !source.isValid(params.get("ValidSource").split(","), hostCard.getController(), hostCard, null)) { - return false; - } - - if (params.containsKey("Activator") && (activator != null) - && !activator.isValid(params.get("Activator"), hostCard.getController(), hostCard, spellAbility)) { - return false; - } - - if (spellAbility.getParam("ValidTgts")!=null && - (params.containsKey("SourceCanOnlyTarget") - && (!spellAbility.getParam("ValidTgts").contains(params.get("SourceCanOnlyTarget")) - || spellAbility.getParam("ValidTgts").contains(",")) - || spellAbility.getParam("ValidTgts").contains("non" + params.get("SourceCanOnlyTarget") - ) - ) - ){ - return false; - } - - if (params.containsKey("Hexproof") && (activator != null)) { + if (st.hasParam("Hexproof") && (activator != null)) { for (String k : activator.getKeywords()) { if (k.startsWith("IgnoreHexproof")) { String[] m = k.split(":"); @@ -106,8 +83,81 @@ public class StaticAbilityCantTarget { } } } + if (st.hasParam("Shroud") && (activator != null)) { + for (String k : activator.getKeywords()) { + if (k.startsWith("IgnoreShroud")) { + String[] m = k.split(":"); + if (card.isValid(m[1].split(","), activator, source, spellAbility)) { + return false; + } + } + } + } + + return common(st, spellAbility); + } + + public static boolean applyCantTargetAbility(final StaticAbility st, final Player player, + final SpellAbility spellAbility) { + final Card hostCard = st.getHostCard(); + final Card source = spellAbility.getHostCard(); + final Player activator = spellAbility.getActivatingPlayer(); + + if (st.hasParam("ValidCard") || st.hasParam("AffectedZone")) { + return false; + } + + if (st.hasParam("ValidPlayer") + && !player.isValid(st.getParam("ValidPlayer").split(","), hostCard.getController(), hostCard, null)) { + return false; + } + + + if (st.hasParam("Hexproof") && (activator != null)) { + for (String k : activator.getKeywords()) { + if (k.startsWith("IgnoreHexproof")) { + String[] m = k.split(":"); + if (player.isValid(m[1].split(","), activator, source, spellAbility)) { + return false; + } + } + } + } return true; } + protected static boolean common(final StaticAbility st, final SpellAbility spellAbility) { + final Card hostCard = st.getHostCard(); + final Card source = spellAbility.getHostCard(); + final Player activator = spellAbility.getActivatingPlayer(); + + if (st.hasParam("ValidSA") + && !spellAbility.isValid(st.getParam("ValidSA").split(","), hostCard.getController(), hostCard, spellAbility)) { + return false; + } + + if (st.hasParam("ValidSource") + && !source.isValid(st.getParam("ValidSource").split(","), hostCard.getController(), hostCard, null)) { + return false; + } + + if (st.hasParam("Activator") && (activator != null) + && !activator.isValid(st.getParam("Activator"), hostCard.getController(), hostCard, spellAbility)) { + return false; + } + + if (spellAbility.hasParam("ValidTgts") && + (st.hasParam("SourceCanOnlyTarget") + && (!spellAbility.getParam("ValidTgts").contains(st.getParam("SourceCanOnlyTarget")) + || spellAbility.getParam("ValidTgts").contains(",")) + || spellAbility.getParam("ValidTgts").contains("non" + st.getParam("SourceCanOnlyTarget") + ) + ) + ){ + 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 4ec308f4e5b..b9df47db469 100644 --- a/forge-gui/res/cardsfolder/a/autumn_willow.txt +++ b/forge-gui/res/cardsfolder/a/autumn_willow.txt @@ -3,7 +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$ Can target CardUIDSource with spells and abilities as though it didn't have shroud. | DefinedKW$ CardUIDSource | 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$ Pump | Cost$ G | ValidTgts$ Player | Defined$ Targeted | TgtPrompt$ Select target player to be able to target Autumn Willow | KW$ IgnoreShroud:Card.CardUIDSource | DefinedKW$ CardUIDSource | UntilHostLeavesPlayOrEOT$ True | 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. AI:RemoveDeck:All SVar:Picture:http://www.wizards.com/global/images/magic/general/autumn_willow.jpg 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/p/peace_talks.txt b/forge-gui/res/cardsfolder/p/peace_talks.txt index 37e12faf05b..a3305e52628 100644 --- a/forge-gui/res/cardsfolder/p/peace_talks.txt +++ b/forge-gui/res/cardsfolder/p/peace_talks.txt @@ -4,6 +4,6 @@ Types:Sorcery A:SP$ Effect | Cost$ 1 W | Name$ Peace Talks Effect | StaticAbilities$ STCantAttack,STCantTarget,STCantTargetPlayer | Duration$ ThisTurnAndNextTurn | SpellDescription$ This turn and next turn, creatures can't attack, and players and permanents can't be the targets of spells or activated abilities. SVar:STCantAttack:Mode$ CantAttack | EffectZone$ Command | ValidCard$ Creature | Description$ Creatures can't attack. SVar:STCantTarget:Mode$ CantTarget | ValidCard$ Permanent | EffectZone$ Command | ValidSA$ Spell,Activated | Description$ Permanents can't be the targets of spells or activated abilities. -SVar:STCantTargetPlayer:Mode$ Continuous | Affected$ Player | EffectZone$ Command | AddKeyword$ You can't be the targets of spells or activated abilities | Description$ Players can't be the targets of spells or activated abilities. +SVar:STCantTargetPlayer:Mode$ CantTarget | ValidPlayer$ Player | EffectZone$ Command | ValidSA$ Spell,Activated | Description$Players can't be the targets of spells or activated abilities. SVar:Picture:http://www.wizards.com/global/images/magic/general/peace_talks.jpg Oracle:This turn and next turn, creatures can't attack, and players and permanents can't be the targets of spells or activated abilities. diff --git a/forge-gui/res/cardsfolder/s/spectral_shield.txt b/forge-gui/res/cardsfolder/s/spectral_shield.txt index f37807ffe07..ee34f2530c8 100644 --- a/forge-gui/res/cardsfolder/s/spectral_shield.txt +++ b/forge-gui/res/cardsfolder/s/spectral_shield.txt @@ -3,6 +3,7 @@ ManaCost:1 W U Types:Enchantment Aura K:Enchant creature A:SP$ Attach | Cost$ 1 W U | ValidTgts$ Creature | AILogic$ Pump -S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddToughness$ 2 | AddHiddenKeyword$ CARDNAME can't be the target of spells. | Description$ Enchanted creature gets +0/+2 and can't be the target of spells. +S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddToughness$ 2 | Description$ Enchanted creature gets +0/+2. +S:Mode$ CantTarget | ValidCard$ Creature.EnchantedBy | ValidSA$ Spell | Description$ Enchanted creature can't be the target of spells. SVar:Picture:http://www.wizards.com/global/images/magic/general/spectral_shield.jpg Oracle:Enchant creature\nEnchanted creature gets +0/+2 and can't be the target of spells. diff --git a/forge-gui/res/cardsfolder/v/veil_of_summer.txt b/forge-gui/res/cardsfolder/v/veil_of_summer.txt index 54941da97e1..d0124692772 100644 --- a/forge-gui/res/cardsfolder/v/veil_of_summer.txt +++ b/forge-gui/res/cardsfolder/v/veil_of_summer.txt @@ -1,8 +1,8 @@ Name:Veil of Summer ManaCost:G Types:Instant -A:SP$ Draw | Cost$ G | Defined$ You | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | SubAbility$ DBEffect | SpellDescription$ Draw a card if an opponent has cast a blue or black spell this turn. Spells you control can't be countered this turn. You and permanents you control gain hexproof from blue and from black until end of turn. (You and they can't be the targets of blue or black spells or abilities your opponents control.) -SVar:DBEffect:DB$ Effect | Name$ CARDNAME Effect | StaticAbilities$ AntiMagic | SubAbility$ DBPump +A:SP$ Draw | Cost$ G | Defined$ You | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 |References$ X | SubAbility$ DBEffect | StackDescription$ SpellDescription | SpellDescription$ Draw a card if an opponent has cast a blue or black spell this turn. Spells you control can't be countered this turn. You and permanents you control gain hexproof from blue and from black until end of turn. (You and they can't be the targets of blue or black spells or abilities your opponents control.) +SVar:DBEffect:DB$ Effect | StaticAbilities$ AntiMagic | SubAbility$ DBPump SVar:AntiMagic:Mode$ Continuous | Affected$ Card.YouCtrl | AffectedZone$ Stack | EffectZone$ Command | AddHiddenKeyword$ CARDNAME can't be countered. | Description$ Spells you control can't be countered this turn. SVar:DBPump:DB$ Pump | Defined$ You | KW$ Hexproof:Card.Black:black & Hexproof:Card.Blue:blue | SubAbility$ DBPumpAll SVar:DBPumpAll:DB$ PumpAll | ValidCards$ Permanent.YouCtrl | KW$ Hexproof:Card.Black:black & Hexproof:Card.Blue:blue