Commit 06b9dffa authored by Hans Mackowiak's avatar Hans Mackowiak

Player keyword rework

parent 173c9ac5
......@@ -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;
......
......@@ -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);
......
......@@ -5618,34 +5618,7 @@ public class Card extends GameEntity implements Comparable<Card> {
}
final Card source = sa.getHostCard();
final MutableBoolean result = new MutableBoolean(true);
visitKeywords(currentState, new Visitor<KeywordInterface>() {
@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();
......
......@@ -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];
......
......@@ -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<T extends 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<T extends 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)
......
......@@ -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);
......
......@@ -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;
/**
* <p>
......@@ -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<Trigger> getTriggers() {
List<Trigger> result = Lists.newArrayList();
for (KeywordInterface k : this.keywords.getValues()) {
result.addAll(k.getTriggers());
}
return result;
}
/**
* @return the replacements
*/
public Collection<ReplacementEffect> getReplacements() {
List<ReplacementEffect> result = Lists.newArrayList();
for (KeywordInterface k : this.keywords.getValues()) {
result.addAll(k.getReplacements());
}
return result;
}
/**
* @return the abilities
*/
public Collection<SpellAbility> getAbilities() {
List<SpellAbility> result = Lists.newArrayList();
for (KeywordInterface k : this.keywords.getValues()) {
result.addAll(k.getAbilities());
}
return result;
}
/**
* @return the staticAbilities
*/
public Collection<StaticAbility> getStaticAbilities() {
List<StaticAbility> result = Lists.newArrayList();
for (KeywordInterface k : this.keywords.getValues()) {
result.addAll(k.getStaticAbilities());
}
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
......
......@@ -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<Player> {
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<Player> {
public final void addChangedKeywords(final List<String> addKeywords, final List<String> 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<Player> {
for (final Entry<Long, KeywordsChange> 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<Player> {
@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<Player> {
|| !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;
}
}
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) {
}
}
......@@ -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
......
......@@ -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 <http://www.gnu.org/licenses/>.
*/
......@@ -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<String, String> 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,42 +66,58 @@ public class StaticAbilityCantTarget {
}
}
if (params.containsKey("ValidSA")
&& !spellAbility.isValid(params.get("ValidSA").split(","), hostCard.getController(), hostCard, spellAbility)) {
return false;
}
if (params.containsKey("ValidCard")
&& !card.isValid(params.get("ValidCard").split(","), hostCard.getController(), hostCard, null)) {
if (st.hasParam("ValidCard")
&& !card.isValid(st.getParam("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 (st.hasParam("Hexproof") && (activator != null)) {
for (String k : activator.getKeywords()) {
if (k.startsWith("IgnoreHexproof")) {
String[] m = k.split(":");
if (card.isValid(m[1].split(","), activator, source, spellAbility)) {
return false;
}
}
}
}
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;
}
}
}
}
if (params.containsKey("Activator") && (activator != null)
&& !activator.isValid(params.get("Activator"), hostCard.getController(), hostCard, spellAbility)) {
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 (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")
)
)
){
if (st.hasParam("ValidPlayer")
&& !player.isValid(st.getParam("ValidPlayer").split(","), hostCard.getController(), hostCard, null)) {
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(":");
if (card.isValid(m[1].split(","), activator, source, spellAbility)) {
if (player.isValid(m[1].split(","), activator, source, spellAbility)) {
return false;
}
}
......@@ -110,4 +127,37 @@ public class StaticAbilityCantTarget {
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;
}
}
......@@ -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.
......@@ -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.
......@@ -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.
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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment