Merge branch 'bloodyCardTraits' into 'master'

CardTaits: make cardtraits inside LKI has the same id's as the in the original

See merge request core-developers/forge!197
This commit is contained in:
Michael Kamensky
2018-02-14 03:28:25 +00:00
36 changed files with 290 additions and 266 deletions

View File

@@ -2466,7 +2466,7 @@ public class ComputerUtilCombat {
for (SpellAbility sa : original.getSpellAbilities()) { for (SpellAbility sa : original.getSpellAbilities()) {
if (sa.getApi() == ApiType.SetState && ComputerUtilCost.canPayCost(sa, original.getController())) { if (sa.getApi() == ApiType.SetState && ComputerUtilCost.canPayCost(sa, original.getController())) {
Card transformed = CardUtil.getLKICopy(original); Card transformed = CardUtil.getLKICopy(original);
transformed.getCurrentState().copyFrom(original, original.getAlternateState()); transformed.getCurrentState().copyFrom(original.getAlternateState(), true);
transformed.updateStateForView(); transformed.updateStateForView();
return transformed; return transformed;
} }

View File

@@ -88,9 +88,9 @@ public class ChooseCardNameAi extends SpellAbilityAi {
Card copy = CardUtil.getLKICopy(card); Card copy = CardUtil.getLKICopy(card);
// for calcing i need only one split side // for calcing i need only one split side
if (isOther) { if (isOther) {
copy.getCurrentState().copyFrom(card, card.getState(CardStateName.RightSplit)); copy.getCurrentState().copyFrom(card.getState(CardStateName.RightSplit), true);
} else { } else {
copy.getCurrentState().copyFrom(card, card.getState(CardStateName.LeftSplit)); copy.getCurrentState().copyFrom(card.getState(CardStateName.LeftSplit), true);
} }
copy.updateStateForView(); copy.updateStateForView();

View File

@@ -167,7 +167,7 @@ public class SetStateAi extends SpellAbilityAi {
// need a copy for evaluation // need a copy for evaluation
Card transformed = CardUtil.getLKICopy(card); Card transformed = CardUtil.getLKICopy(card);
transformed.getCurrentState().copyFrom(card, card.getAlternateState()); transformed.getCurrentState().copyFrom(card.getAlternateState(), true);
transformed.updateStateForView(); transformed.updateStateForView();
// TODO: compareCards assumes that a creature will transform into a creature. Need to improve this // TODO: compareCards assumes that a creature will transform into a creature. Need to improve this

View File

@@ -29,7 +29,6 @@ import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.player.RegisteredPlayer; import forge.game.player.RegisteredPlayer;
import forge.game.spellability.AbilityActivated;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityRestriction; import forge.game.spellability.SpellAbilityRestriction;
import forge.game.spellability.SpellAbilityStackInstance; import forge.game.spellability.SpellAbilityStackInstance;
@@ -263,15 +262,8 @@ public class GameCopier {
newCard.addStaticAbility(stAb); newCard.addStaticAbility(stAb);
} }
for (SpellAbility sa : c.getSpellAbilities()) { for (SpellAbility sa : c.getSpellAbilities()) {
SpellAbility saCopy; SpellAbility saCopy = sa.copy(newCard, true);
if (sa instanceof AbilityActivated) {
saCopy = ((AbilityActivated)sa).getCopy();
} else {
saCopy = sa.copy();
}
if (saCopy != null) { if (saCopy != null) {
saCopy.setHostCard(newCard);
newCard.addSpellAbility(saCopy); newCard.addSpellAbility(saCopy);
} else { } else {
System.err.println(sa.toString()); System.err.println(sa.toString());

View File

@@ -233,7 +233,7 @@ public final class GameActionUtil {
alternatives.add(newSA); alternatives.add(newSA);
} }
if (sa.hasParam("Equip") && sa instanceof AbilityActivated && keyword.equals("EquipInstantSpeed")) { if (sa.hasParam("Equip") && sa instanceof AbilityActivated && keyword.equals("EquipInstantSpeed")) {
final SpellAbility newSA = ((AbilityActivated) sa).getCopy(); final SpellAbility newSA = sa.copy();
SpellAbilityRestriction sar = newSA.getRestrictions(); SpellAbilityRestriction sar = newSA.getRestrictions();
sar.setSorcerySpeed(false); sar.setSorcerySpeed(false);
sar.setInstantSpeed(true); sar.setInstantSpeed(true);

View File

@@ -11,7 +11,7 @@ import forge.game.zone.ZoneType;
/** /**
* Created by Hellfish on 2014-02-09. * Created by Hellfish on 2014-02-09.
*/ */
public abstract class TriggerReplacementBase extends CardTraitBase { public abstract class TriggerReplacementBase extends CardTraitBase implements IIdentifiable, Cloneable {
protected EnumSet<ZoneType> validHostZones; protected EnumSet<ZoneType> validHostZones;
/** The overriding ability. */ /** The overriding ability. */

View File

@@ -5,7 +5,6 @@ import forge.game.ability.effects.ChangeZoneEffect;
import forge.game.ability.effects.ManaEffect; import forge.game.ability.effects.ManaEffect;
import forge.game.ability.effects.ManaReflectedEffect; import forge.game.ability.effects.ManaReflectedEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardFactory;
import forge.game.cost.Cost; import forge.game.cost.Cost;
import forge.game.spellability.AbilityActivated; import forge.game.spellability.AbilityActivated;
import forge.game.spellability.AbilityManaPart; import forge.game.spellability.AbilityManaPart;
@@ -41,17 +40,6 @@ public class AbilityApiBased extends AbilityActivated {
return effect.getStackDescriptionWithSubs(mapParams, this); return effect.getStackDescriptionWithSubs(mapParams, this);
} }
/* (non-Javadoc)
* @see forge.card.spellability.AbilityActivated#getCopy()
*/
@Override
public AbilityActivated getCopy() {
TargetRestrictions tgt = getTargetRestrictions() == null ? null : new TargetRestrictions(getTargetRestrictions());
AbilityActivated res = new AbilityApiBased(api, getHostCard(), getPayCosts(), tgt, mapParams);
CardFactory.copySpellAbility(this, res, getHostCard());
return res;
}
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.spellability.SpellAbility#resolve() * @see forge.card.spellability.SpellAbility#resolve()
*/ */

View File

@@ -195,7 +195,7 @@ public class CharmEffect extends SpellAbilityEffect {
for (AbilitySub sub : chosen) { for (AbilitySub sub : chosen) {
// Clone the chosen, just in case the some subAb gets chosen multiple times // Clone the chosen, just in case the some subAb gets chosen multiple times
AbilitySub clone = (AbilitySub)sub.getCopy(); AbilitySub clone = (AbilitySub)sub.copy();
// update ActivatingPlayer // update ActivatingPlayer
clone.setActivatingPlayer(sa.getActivatingPlayer()); clone.setActivatingPlayer(sa.getActivatingPlayer());

View File

@@ -141,6 +141,10 @@ public class PumpEffect extends SpellAbilityEffect {
} }
} }
/*
* (non-Javadoc)
* @see forge.game.ability.SpellAbilityEffect#getStackDescription(forge.game.spellability.SpellAbility)
*/
@Override @Override
protected String getStackDescription(final SpellAbility sa) { protected String getStackDescription(final SpellAbility sa) {

View File

@@ -822,17 +822,18 @@ public class Card extends GameEntity implements Comparable<Card> {
public final FCollectionView<Trigger> getTriggers() { public final FCollectionView<Trigger> getTriggers() {
return currentState.getTriggers(); return currentState.getTriggers();
} }
// only used for LKI
public final void setTriggers(final Iterable<Trigger> trigs, boolean intrinsicOnly) { public final void setTriggers(final Iterable<Trigger> trigs, boolean intrinsicOnly) {
final FCollection<Trigger> copyList = new FCollection<>(); final FCollection<Trigger> copyList = new FCollection<>();
for (final Trigger t : trigs) { for (final Trigger t : trigs) {
if (!intrinsicOnly || t.isIntrinsic()) { if (!intrinsicOnly || t.isIntrinsic()) {
copyList.add(t.getCopyForHostCard(this)); copyList.add(t.copy(this, true));
} }
} }
currentState.setTriggers(copyList); currentState.setTriggers(copyList);
} }
public final Trigger addTrigger(final Trigger t) { public final Trigger addTrigger(final Trigger t) {
final Trigger newtrig = t.getCopyForHostCard(this); final Trigger newtrig = t.copy(this, false);
currentState.addTrigger(newtrig); currentState.addTrigger(newtrig);
return newtrig; return newtrig;
} }
@@ -5171,16 +5172,14 @@ public class Card extends GameEntity implements Comparable<Card> {
currentState.clearReplacementEffects(); currentState.clearReplacementEffects();
for (final ReplacementEffect replacementEffect : res) { for (final ReplacementEffect replacementEffect : res) {
if (replacementEffect.isIntrinsic()) { if (replacementEffect.isIntrinsic()) {
addReplacementEffect(replacementEffect); addReplacementEffect(replacementEffect.copy(this, false));
} }
} }
} }
public ReplacementEffect addReplacementEffect(final ReplacementEffect replacementEffect) { public ReplacementEffect addReplacementEffect(final ReplacementEffect replacementEffect) {
final ReplacementEffect replacementEffectCopy = replacementEffect.getCopy(); // doubtful - every caller provides a newly parsed instance, why copy? currentState.addReplacementEffect(replacementEffect);
replacementEffectCopy.setHostCard(this); return replacementEffect;
currentState.addReplacementEffect(replacementEffectCopy);
return replacementEffectCopy;
} }
public void removeReplacementEffect(ReplacementEffect replacementEffect) { public void removeReplacementEffect(ReplacementEffect replacementEffect) {
currentState.removeReplacementEffect(replacementEffect); currentState.removeReplacementEffect(replacementEffect);
@@ -5192,6 +5191,17 @@ public class Card extends GameEntity implements Comparable<Card> {
} }
} }
public boolean hasReplacementEffect(final ReplacementEffect re) {
return currentState.hasReplacementEffect(re);
}
public boolean hasReplacementEffect(final int id) {
return currentState.hasReplacementEffect(id);
}
public ReplacementEffect getReplacementEffect(final int id) {
return currentState.getReplacementEffect(id);
}
/** /**
* Returns what zone this card was cast from (from what zone it was moved to the stack). * Returns what zone this card was cast from (from what zone it was moved to the stack).
*/ */

View File

@@ -184,21 +184,10 @@ public class CardFactory {
c.setCopiedSpell(true); c.setCopiedSpell(true);
final SpellAbility copySA; final SpellAbility copySA;
if (sa instanceof AbilityActivated) { if (sa.isTrigger()) {
copySA = ((AbilityActivated)sa).getCopy();
copySA.setHostCard(original);
}
else if (sa.isTrigger()) {
copySA = getCopiedTriggeredAbility(sa); copySA = getCopiedTriggeredAbility(sa);
} } else {
else { copySA = sa.copy(c, false);
copySA = sa.copy();
AbilitySub subSA = copySA.getSubAbility();
while (subSA != null) {
subSA.setCopied(true);
subSA = subSA.getSubAbility();
}
copySA.setHostCard(c);
} }
c.getCurrentState().setNonManaAbilities(copySA); c.getCurrentState().setNonManaAbilities(copySA);
copySA.setCopied(true); copySA.setCopied(true);
@@ -577,27 +566,28 @@ public class CardFactory {
to.addAlternateState(toState, updateView); to.addAlternateState(toState, updateView);
} }
final CardState toCharacteristics = to.getState(toState), fromCharacteristics = from.getState(fromState); final CardState toCharacteristics = to.getState(toState), fromCharacteristics = from.getState(fromState);
toCharacteristics.copyFrom(from, fromCharacteristics); toCharacteristics.copyFrom(fromCharacteristics, false);
} }
public static void copySpellAbility(SpellAbility from, SpellAbility to, final Card host) { public static void copySpellAbility(SpellAbility from, SpellAbility to, final Card host, final boolean lki) {
if (from.getActivatingPlayer() != null) {
to.setActivatingPlayer(from.getActivatingPlayer()); if (from.getTargetRestrictions() != null) {
to.setTargetRestrictions(from.getTargetRestrictions());
} }
to.setDescription(from.getOriginalDescription()); to.setDescription(from.getOriginalDescription());
to.setStackDescription(from.getOriginalStackDescription()); to.setStackDescription(from.getOriginalStackDescription());
if (from.getSubAbility() != null) { if (from.getSubAbility() != null) {
to.setSubAbility(from.getSubAbility().getCopy(host)); to.setSubAbility((AbilitySub) from.getSubAbility().copy(host, lki));
} }
for (Map.Entry<String, AbilitySub> e : from.getAdditionalAbilities().entrySet()) { for (Map.Entry<String, AbilitySub> e : from.getAdditionalAbilities().entrySet()) {
to.setAdditionalAbility(e.getKey(), e.getValue().getCopy(host)); to.setAdditionalAbility(e.getKey(), (AbilitySub) e.getValue().copy(host, lki));
} }
for (Map.Entry<String, List<AbilitySub>> e : from.getAdditionalAbilityLists().entrySet()) { for (Map.Entry<String, List<AbilitySub>> e : from.getAdditionalAbilityLists().entrySet()) {
to.setAdditionalAbilityList(e.getKey(), Lists.transform(e.getValue(), new Function<AbilitySub, AbilitySub>() { to.setAdditionalAbilityList(e.getKey(), Lists.transform(e.getValue(), new Function<AbilitySub, AbilitySub>() {
@Override @Override
public AbilitySub apply(AbilitySub input) { public AbilitySub apply(AbilitySub input) {
return input.getCopy(host); return (AbilitySub) input.copy(host, lki);
} }
})); }));
} }
@@ -608,6 +598,11 @@ public class CardFactory {
to.setConditions((SpellAbilityCondition) from.getConditions().copy()); to.setConditions((SpellAbilityCondition) from.getConditions().copy());
} }
// do this after other abilties are copied
if (from.getActivatingPlayer() != null) {
to.setActivatingPlayer(from.getActivatingPlayer(), lki);
}
for (String sVar : from.getSVars()) { for (String sVar : from.getSVars()) {
to.setSVar(sVar, from.getSVar(sVar)); to.setSVar(sVar, from.getSVar(sVar));
} }

View File

@@ -170,10 +170,10 @@ public class CardState extends GameObject {
public final boolean hasIntrinsicKeyword(String k) { public final boolean hasIntrinsicKeyword(String k) {
return intrinsicKeywords.contains(k); return intrinsicKeywords.contains(k);
} }
public final void setIntrinsicKeywords(final Iterable<KeywordInterface> intrinsicKeyword0) { public final void setIntrinsicKeywords(final Iterable<KeywordInterface> intrinsicKeyword0, final boolean lki) {
intrinsicKeywords.clear(); intrinsicKeywords.clear();
for (KeywordInterface k : intrinsicKeyword0) { for (KeywordInterface k : intrinsicKeyword0) {
intrinsicKeywords.insert(k.copy(card)); intrinsicKeywords.insert(k.copy(card, lki));
} }
} }
@@ -367,6 +367,24 @@ public class CardState extends GameObject {
return getReplacementEffects().contains(re); return getReplacementEffects().contains(re);
} }
public final boolean hasReplacementEffect(final int id) {
for (final ReplacementEffect r : getReplacementEffects()) {
if (id == r.getId()) {
return true;
}
}
return false;
}
public final ReplacementEffect getReplacementEffect(final int id) {
for (final ReplacementEffect r : getReplacementEffects()) {
if (id == r.getId()) {
return r;
}
}
return null;
}
public final Map<String, String> getSVars() { public final Map<String, String> getSVars() {
return sVars; return sVars;
} }
@@ -406,7 +424,7 @@ public class CardState extends GameObject {
return 0; return 0;
} }
public final void copyFrom(final Card c, final CardState source) { public final void copyFrom(final CardState source, final boolean lki) {
// Makes a "deeper" copy of a CardState object // Makes a "deeper" copy of a CardState object
setName(source.getName()); setName(source.getName());
setType(source.type); setType(source.type);
@@ -419,36 +437,30 @@ public class CardState extends GameObject {
manaAbilities.clear(); manaAbilities.clear();
for (SpellAbility sa : source.manaAbilities) { for (SpellAbility sa : source.manaAbilities) {
if (sa.isIntrinsic()) { if (sa.isIntrinsic()) {
SpellAbility saCopy = sa.copy(); manaAbilities.add(sa.copy(card, lki));
saCopy.setHostCard(card); // update HostCard
manaAbilities.add(saCopy);
} }
} }
nonManaAbilities.clear(); nonManaAbilities.clear();
for (SpellAbility sa : source.nonManaAbilities) { for (SpellAbility sa : source.nonManaAbilities) {
if (sa.isIntrinsic()) { if (sa.isIntrinsic()) {
SpellAbility saCopy = sa.copy(); nonManaAbilities.add(sa.copy(card, lki));
saCopy.setHostCard(card); // update HostCard
nonManaAbilities.add(saCopy);
} }
} }
setIntrinsicKeywords(source.intrinsicKeywords.getValues()); setIntrinsicKeywords(source.intrinsicKeywords.getValues(), lki);
setImageKey(source.getImageKey()); setImageKey(source.getImageKey());
setRarity(source.rarity); setRarity(source.rarity);
setSetCode(source.setCode); setSetCode(source.setCode);
triggers.clear(); triggers.clear();
for (Trigger tr : source.triggers) { for (Trigger tr : source.triggers) {
triggers.add(tr.getCopyForHostCard(card)); triggers.add(tr.copy(card, lki));
} }
replacementEffects.clear(); replacementEffects.clear();
for (ReplacementEffect re : source.replacementEffects) { for (ReplacementEffect re : source.replacementEffects) {
ReplacementEffect reCopy = re.getCopy(); replacementEffects.add(re.copy(card, lki));
reCopy.setHostCard(card);
replacementEffects.add(reCopy);
} }
staticAbilities.clear(); staticAbilities.clear();
@@ -456,7 +468,6 @@ public class CardState extends GameObject {
StaticAbility saCopy = new StaticAbility(sa, this.card); StaticAbility saCopy = new StaticAbility(sa, this.card);
staticAbilities.add(saCopy); staticAbilities.add(saCopy);
} }
view.updateKeywords(c, this);
} }

View File

@@ -211,19 +211,18 @@ public final class CardUtil {
// used for the purpose of cards that care about the zone the card was known to be in last // used for the purpose of cards that care about the zone the card was known to be in last
newCopy.setLastKnownZone(in.getLastKnownZone()); newCopy.setLastKnownZone(in.getLastKnownZone());
newCopy.getCurrentState().copyFrom(in, in.getState(in.getCurrentStateName())); newCopy.getCurrentState().copyFrom(in.getState(in.getCurrentStateName()), true);
if (in.isCloned()) { if (in.isCloned()) {
newCopy.addAlternateState(CardStateName.Cloner, false); newCopy.addAlternateState(CardStateName.Cloner, false);
newCopy.getState(CardStateName.Cloner).copyFrom(in, in.getState(CardStateName.Cloner)); newCopy.getState(CardStateName.Cloner).copyFrom(in.getState(CardStateName.Cloner), true);
} }
newCopy.setType(new CardType(in.getType())); newCopy.setType(new CardType(in.getType()));
newCopy.setToken(in.isToken()); newCopy.setToken(in.isToken());
newCopy.setTriggers(in.getTriggers(), false); newCopy.setTriggers(in.getTriggers(), false);
for (SpellAbility sa : in.getSpellAbilities()) { for (SpellAbility sa : in.getSpellAbilities()) {
newCopy.addSpellAbility(sa); newCopy.addSpellAbility(sa.copy(newCopy, true));
sa.setHostCard(in);
} }
// lock in the current P/T without bonus from counters // lock in the current P/T without bonus from counters
@@ -263,6 +262,11 @@ public final class CardUtil {
newCopy.setMeldedWith(in.getMeldedWith()); newCopy.setMeldedWith(in.getMeldedWith());
// update keyword cache on all states
for (CardStateName s : newCopy.getStates()) {
newCopy.updateKeywordsCache(newCopy.getState(s));
}
return newCopy; return newCopy;
} }

View File

@@ -167,6 +167,17 @@ public class KeywordCollection implements Iterable<String>, Serializable {
}; };
} }
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(map.values());
return sb.toString();
}
public KeywordCollectionView getView() { public KeywordCollectionView getView() {
if (view == null) { if (view == null) {
view = new KeywordCollectionView(); view = new KeywordCollectionView();

View File

@@ -180,26 +180,23 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
* (non-Javadoc) * (non-Javadoc)
* @see forge.game.keyword.KeywordInterface#copy() * @see forge.game.keyword.KeywordInterface#copy()
*/ */
public KeywordInterface copy(final Card host) { public KeywordInterface copy(final Card host, final boolean lki) {
try { try {
KeywordInstance<?> result = (KeywordInstance<?>) super.clone(); KeywordInstance<?> result = (KeywordInstance<?>) super.clone();
result.abilities = Lists.newArrayList(); result.abilities = Lists.newArrayList();
for (SpellAbility sa : this.abilities) { for (SpellAbility sa : this.abilities) {
SpellAbility saCopy = sa.copy(host); result.abilities.add(sa.copy(host, lki));
result.abilities.add(saCopy);
} }
result.triggers = Lists.newArrayList(); result.triggers = Lists.newArrayList();
for (Trigger tr : this.triggers) { for (Trigger tr : this.triggers) {
result.triggers.add(tr.getCopyForHostCard(host)); result.triggers.add(tr.copy(host, lki));
} }
result.replacements = Lists.newArrayList(); result.replacements = Lists.newArrayList();
for (ReplacementEffect re : this.replacements) { for (ReplacementEffect re : this.replacements) {
ReplacementEffect reCopy = re.getCopy(); result.replacements.add(re.copy(host, lki));
reCopy.setHostCard(host);
result.replacements.add(reCopy);
} }
result.staticAbilities = Lists.newArrayList(); result.staticAbilities = Lists.newArrayList();
@@ -212,4 +209,12 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
throw new RuntimeException("KeywordInstance : clone() error, " + ex); throw new RuntimeException("KeywordInstance : clone() error, " + ex);
} }
} }
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return this.getOriginal();
}
} }

View File

@@ -49,5 +49,5 @@ public interface KeywordInterface extends Cloneable {
*/ */
public Collection<StaticAbility> getStaticAbilities(); public Collection<StaticAbility> getStaticAbilities();
public KeywordInterface copy(final Card host); public KeywordInterface copy(final Card host, final boolean lki);
} }

View File

@@ -1,12 +1,16 @@
package forge.game.replacement; package forge.game.replacement;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardUtil;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import java.util.Map; import java.util.Map;
import com.google.common.collect.Sets;
/** /**
* TODO: Write javadoc for this type. * TODO: Write javadoc for this type.
* *
@@ -60,8 +64,9 @@ public class ReplaceMoved extends ReplacementEffect {
if (hasParam("Destination")) { if (hasParam("Destination")) {
matchedZone = false; matchedZone = false;
ZoneType zt = (ZoneType) runParams.get("Destination");
for(ZoneType z : ZoneType.listValueOf(getParam("Destination"))) { for(ZoneType z : ZoneType.listValueOf(getParam("Destination"))) {
if(z == (ZoneType) runParams.get("Destination")) if(z == zt)
matchedZone = true; matchedZone = true;
} }
@@ -69,6 +74,20 @@ public class ReplaceMoved extends ReplacementEffect {
{ {
return false; return false;
} }
if (zt.equals(ZoneType.Battlefield)) {
// would be an etb replacement effect that enters the battlefield
Card lki = CardUtil.getLKICopy((Card) runParams.get("Affected"));
lki.setLastKnownZone(lki.getController().getZone(zt));
CardCollection preList = new CardCollection(lki);
getHostCard().getGame().getAction().checkStaticAbilities(false, Sets.newHashSet(lki), preList);
// check if when entering the battlefield would still has this RE or is suppressed
if (!lki.hasReplacementEffect(this) || lki.getReplacementEffect(getId()).isSuppressed()) {
return false;
}
}
} }
if (hasParam("ExcludeDestination")) { if (hasParam("ExcludeDestination")) {

View File

@@ -19,11 +19,9 @@ package forge.game.replacement;
import forge.game.Game; import forge.game.Game;
import forge.game.TriggerReplacementBase; import forge.game.TriggerReplacementBase;
import forge.game.ability.AbilityApiBased;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.util.TextUtil; import forge.util.TextUtil;
@@ -35,12 +33,37 @@ import java.util.Map;
* *
*/ */
public abstract class ReplacementEffect extends TriggerReplacementBase { public abstract class ReplacementEffect extends TriggerReplacementBase {
private static int maxId = 0;
private static int nextId() { return ++maxId; }
/** The ID. */
private int id;
private ReplacementLayer layer = ReplacementLayer.None; private ReplacementLayer layer = ReplacementLayer.None;
/** The has run. */ /** The has run. */
private boolean hasRun = false; private boolean hasRun = false;
/**
* Gets the id.
*
* @return the id
*/
public int getId() {
return this.id;
}
/**
* <p>
* setID.
* </p>
*
* @param id
* a int.
*/
public final void setId(final int id) {
this.id = id;
}
/** /**
* Checks for run. * Checks for run.
* *
@@ -59,6 +82,7 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
* the host * the host
*/ */
public ReplacementEffect(final Map<String, String> map, final Card host, final boolean intrinsic) { public ReplacementEffect(final Map<String, String> map, final Card host, final boolean intrinsic) {
this.id = nextId();
this.intrinsic = intrinsic; this.intrinsic = intrinsic;
originalMapParams.putAll(map); originalMapParams.putAll(map);
mapParams.putAll(map); mapParams.putAll(map);
@@ -133,32 +157,27 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
* *
* @return the copy * @return the copy
*/ */
public final ReplacementEffect getCopy() { public final ReplacementEffect copy(final Card host, final boolean lki) {
final ReplacementType rt = ReplacementType.getTypeFor(this); final ReplacementEffect res = (ReplacementEffect) clone();
final ReplacementEffect res = rt.createReplacement(mapParams, hostCard, intrinsic);
final SpellAbility overridingAbility = this.getOverridingAbility();
if (overridingAbility != null) {
final SpellAbility overridingAbilityCopy;
if (overridingAbility instanceof AbilityApiBased) {
overridingAbilityCopy = ((AbilityApiBased) overridingAbility).getCopy();
} else if (overridingAbility instanceof AbilitySub) {
overridingAbilityCopy = ((AbilitySub) overridingAbility).getCopy();
} else {
System.err.println("Overriding ability of " + hostCard + " of unexpected type " + overridingAbility.getClass());
overridingAbilityCopy = null;
}
if (overridingAbilityCopy != null) {
overridingAbilityCopy.setHostCard(hostCard);
res.setOverridingAbility(overridingAbilityCopy);
}
}
res.setActiveZone(validHostZones);
res.setLayer(getLayer());
res.setTemporary(isTemporary());
for (String key : getSVars()) { for (String key : getSVars()) {
res.setSVar(key, getSVar(key)); res.setSVar(key, getSVar(key));
} }
final SpellAbility sa = this.getOverridingAbility();
if (sa != null) {
final SpellAbility overridingAbilityCopy = sa.copy(host, lki);
if (overridingAbilityCopy != null) {
res.setOverridingAbility(overridingAbilityCopy);
}
}
if (!lki) {
res.setId(nextId());
}
res.setActiveZone(validHostZones);
res.setLayer(getLayer());
res.setTemporary(isTemporary());
return res; return res;
} }
@@ -206,6 +225,29 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
} }
} }
/** {@inheritDoc} */
@Override
public final Object clone() {
try {
return super.clone();
} catch (final Exception ex) {
throw new RuntimeException("ReplacementEffect : clone() error, " + ex);
}
}
/** {@inheritDoc} */
@Override
public final boolean equals(final Object o) {
if (!(o instanceof ReplacementEffect)) {
return false;
}
return this.getId() == ((ReplacementEffect) o).getId();
}
/** {@inheritDoc} */
@Override
public int hashCode() {
return 42 * (42 + this.getId());
}
} }

View File

@@ -61,21 +61,12 @@ public class ReplacementHandler {
decider = ((Card) affected).getController(); decider = ((Card) affected).getController();
} }
ReplacementResult res = run(runParams, ReplacementLayer.Control, decider); // try out all layer
for (ReplacementLayer layer : ReplacementLayer.values()) {
ReplacementResult res = run(runParams, layer, decider);
if (res != ReplacementResult.NotReplaced) { if (res != ReplacementResult.NotReplaced) {
return res; return res;
} }
res = run(runParams, ReplacementLayer.Copy, decider);
if (res != ReplacementResult.NotReplaced) {
return res;
}
res = run(runParams, ReplacementLayer.Other, decider);
if (res != ReplacementResult.NotReplaced) {
return res;
}
res = run(runParams, ReplacementLayer.None, decider);
if (res != ReplacementResult.NotReplaced) {
return res;
} }
return ReplacementResult.NotReplaced; return ReplacementResult.NotReplaced;

View File

@@ -32,16 +32,6 @@ public enum ReplacementType {
clasz = cls; clasz = cls;
} }
public static ReplacementType getTypeFor(ReplacementEffect e) {
final Class<? extends ReplacementEffect> cls = e.getClass();
for (final ReplacementType v : ReplacementType.values()) {
if (v.clasz.equals(cls)) {
return v;
}
}
return null;
}
public static ReplacementType smartValueOf(String value) { public static ReplacementType smartValueOf(String value) {
final String valToCompate = value.trim(); final String valToCompate = value.trim();
for (final ReplacementType v : ReplacementType.values()) { for (final ReplacementType v : ReplacementType.values()) {

View File

@@ -72,10 +72,6 @@ public abstract class AbilityActivated extends SpellAbility implements java.io.S
} }
} }
public abstract AbilityActivated getCopy(); /* {
return null;
}
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public boolean canPlay() { public boolean canPlay() {

View File

@@ -25,7 +25,6 @@ import forge.game.ability.effects.ChangeZoneEffect;
import forge.game.ability.effects.ManaEffect; import forge.game.ability.effects.ManaEffect;
import forge.game.ability.effects.ManaReflectedEffect; import forge.game.ability.effects.ManaReflectedEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardFactory;
import forge.game.cost.Cost; import forge.game.cost.Cost;
import java.util.Map; import java.util.Map;
@@ -102,16 +101,6 @@ public final class AbilitySub extends SpellAbility implements java.io.Serializab
} }
} }
public AbilitySub getCopy() {
return getCopy(getHostCard());
}
public AbilitySub getCopy(Card host) {
TargetRestrictions t = getTargetRestrictions() == null ? null : new TargetRestrictions(getTargetRestrictions());
AbilitySub res = new AbilitySub(api, host, t, mapParams);
CardFactory.copySpellAbility(this, res, host);
return res;
}
@Override @Override
public String getStackDescription() { public String getStackDescription() {
return effect.getStackDescriptionWithSubs(mapParams, this); return effect.getStackDescriptionWithSubs(mapParams, this);

View File

@@ -313,25 +313,26 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
return activatingPlayer; return activatingPlayer;
} }
public void setActivatingPlayer(final Player player) { public void setActivatingPlayer(final Player player) {
setActivatingPlayer(player, false);
}
public void setActivatingPlayer(final Player player, final boolean lki) {
// trickle down activating player // trickle down activating player
activatingPlayer = player; activatingPlayer = player;
if (subAbility != null) { if (subAbility != null) {
subAbility.setActivatingPlayer(player); subAbility.setActivatingPlayer(player, lki);
} }
for (AbilitySub sa : additionalAbilities.values()) { for (AbilitySub sa : additionalAbilities.values()) {
if (sa.getActivatingPlayer() != player) { sa.setActivatingPlayer(player, lki);
sa.setActivatingPlayer(player);
}
} }
for (List<AbilitySub> list : additionalAbilityLists.values()) { for (List<AbilitySub> list : additionalAbilityLists.values()) {
for (AbilitySub sa : list) { for (AbilitySub sa : list) {
if (sa.getActivatingPlayer() != player) { sa.setActivatingPlayer(player, lki);
sa.setActivatingPlayer(player);
}
} }
} }
if (!lki) {
view.updateCanPlay(this, false); view.updateCanPlay(this, false);
} }
}
public Player getDeltrigActivatingPlayer() { public Player getDeltrigActivatingPlayer() {
return deltrigActivatingPlayer; return deltrigActivatingPlayer;
@@ -789,17 +790,18 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
} }
public SpellAbility copy() { public SpellAbility copy() {
return copy(hostCard); return copy(hostCard, false);
} }
public SpellAbility copy(Card host) { public SpellAbility copy(Card host, final boolean lki) {
SpellAbility clone = null; SpellAbility clone = null;
try { try {
clone = (SpellAbility) clone(); clone = (SpellAbility) clone();
clone.id = nextId(); clone.id = lki ? id : nextId();
clone.view = new SpellAbilityView(clone); clone.view = new SpellAbilityView(clone);
// dont use setHostCard to not trigger the not copied parts yet // dont use setHostCard to not trigger the not copied parts yet
clone.hostCard = host; clone.hostCard = host;
if (host != null && host.getGame() != null) { if (!lki && host != null && host.getGame() != null) {
host.getGame().addSpellAbility(clone); host.getGame().addSpellAbility(clone);
} }
// need to clone the maps too so they can be changed // need to clone the maps too so they can be changed
@@ -808,8 +810,11 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
clone.triggeringObjects = Maps.newHashMap(this.triggeringObjects); clone.triggeringObjects = Maps.newHashMap(this.triggeringObjects);
if (getPayCosts() != null) {
clone.setPayCosts(getPayCosts().copy());
}
// run special copy Ability to make a deep copy // run special copy Ability to make a deep copy
CardFactory.copySpellAbility(this, clone, host); CardFactory.copySpellAbility(this, clone, host, lki);
} catch (final CloneNotSupportedException e) { } catch (final CloneNotSupportedException e) {
System.err.println(e); System.err.println(e);
} }
@@ -1109,6 +1114,9 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
} }
public void setCopied(boolean isCopied0) { public void setCopied(boolean isCopied0) {
isCopied = isCopied0; isCopied = isCopied0;
if (this.getSubAbility() != null) {
this.getSubAbility().setCopied(isCopied0);
}
} }
/** /**

View File

@@ -369,12 +369,12 @@ public final class StaticAbilityContinuous {
cardsIGainedAbilitiesFrom = CardLists.getValidCards(cardsIGainedAbilitiesFrom, valids, hostCard.getController(), hostCard, null); cardsIGainedAbilitiesFrom = CardLists.getValidCards(cardsIGainedAbilitiesFrom, valids, hostCard.getController(), hostCard, null);
if (cardsIGainedAbilitiesFrom.size() > 0) { if (cardsIGainedAbilitiesFrom.size() > 0) {
addFullAbs = new ArrayList<SpellAbility>(); addFullAbs = Lists.newArrayList();
for (Card c : cardsIGainedAbilitiesFrom) { for (Card c : cardsIGainedAbilitiesFrom) {
for (SpellAbility sa : c.getSpellAbilities()) { for (SpellAbility sa : c.getSpellAbilities()) {
if (sa instanceof AbilityActivated) { if (sa instanceof AbilityActivated) {
SpellAbility newSA = ((AbilityActivated) sa).getCopy(); SpellAbility newSA = sa.copy(hostCard, false);
if (params.containsKey("GainsAbilitiesLimitPerTurn")) { if (params.containsKey("GainsAbilitiesLimitPerTurn")) {
newSA.setRestrictions(sa.getRestrictions()); newSA.setRestrictions(sa.getRestrictions());
newSA.getRestrictions().setLimitToCheck(params.get("GainsAbilitiesLimitPerTurn")); newSA.getRestrictions().setLimitToCheck(params.get("GainsAbilitiesLimitPerTurn"));
@@ -382,7 +382,6 @@ public final class StaticAbilityContinuous {
newSA.setOriginalHost(c); newSA.setOriginalHost(c);
newSA.setIntrinsic(false); newSA.setIntrinsic(false);
newSA.setTemporary(true); newSA.setTemporary(true);
newSA.setHostCard(hostCard);
addFullAbs.add(newSA); addFullAbs.add(newSA);
} }
} }

View File

@@ -29,7 +29,6 @@ import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.Ability; import forge.game.spellability.Ability;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.OptionalCost; import forge.game.spellability.OptionalCost;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
@@ -49,9 +48,8 @@ import forge.util.TextUtil;
* @version $Id$ * @version $Id$
*/ */
public abstract class Trigger extends TriggerReplacementBase { public abstract class Trigger extends TriggerReplacementBase {
private static int maxId = 0;
/** Constant <code>nextID=0</code>. */ private static int nextId() { return ++maxId; }
private static int nextID = 0;
/** /**
* <p> * <p>
@@ -59,23 +57,12 @@ public abstract class Trigger extends TriggerReplacementBase {
* </p> * </p>
*/ */
public static void resetIDs() { public static void resetIDs() {
Trigger.nextID = 50000; Trigger.maxId = 50000;
} }
/** The ID. */ /** The ID. */
private int id = Trigger.nextID++; private int id;
/**
* <p>
* setID.
* </p>
*
* @param id
* a int.
*/
public final void setID(final int id) {
this.id = id;
}
/** The run params. */ /** The run params. */
private Map<String, Object> runParams; private Map<String, Object> runParams;
@@ -131,9 +118,10 @@ public abstract class Trigger extends TriggerReplacementBase {
* the intrinsic * the intrinsic
*/ */
public Trigger(final Map<String, String> params, final Card host, final boolean intrinsic) { public Trigger(final Map<String, String> params, final Card host, final boolean intrinsic) {
this.id = nextId();
this.intrinsic = intrinsic; this.intrinsic = intrinsic;
this.setRunParams(new HashMap<String, Object>()); this.setRunParams(Maps.newHashMap());
this.originalMapParams.putAll(params); this.originalMapParams.putAll(params);
this.mapParams.putAll(params); this.mapParams.putAll(params);
this.setHostCard(host); this.setHostCard(host);
@@ -469,6 +457,18 @@ public abstract class Trigger extends TriggerReplacementBase {
return this.id; return this.id;
} }
/**
* <p>
* setID.
* </p>
*
* @param id
* a int.
*/
public final void setId(final int id) {
this.id = id;
}
private Ability triggeredSA; private Ability triggeredSA;
/** /**
@@ -516,32 +516,24 @@ public abstract class Trigger extends TriggerReplacementBase {
mode = triggerType; mode = triggerType;
} }
public final Trigger copy(Card newHost, boolean lki) {
final Trigger copy = (Trigger) clone();
public final Trigger getCopyForHostCard(Card newHost) { copy.originalMapParams.putAll(originalMapParams);
final TriggerType tt = TriggerType.getTypeFor(this); copy.mapParams.putAll(originalMapParams);
final Trigger copy = tt.createTrigger(originalMapParams, newHost, intrinsic); copy.setHostCard(newHost);
if (this.getOverridingAbility() != null) { if (getOverridingAbility() != null) {
SpellAbility old = this.getOverridingAbility(); copy.setOverridingAbility(getOverridingAbility().copy(newHost, lki));
SpellAbility sa = old;
// try to copy it if newHost is not the wanted host
final Card oldHost = old.getHostCard();
if (!newHost.equals(oldHost)) {
if (old instanceof AbilitySub) {
sa = ((AbilitySub)old).getCopy();
sa.setHostCard(newHost);
}
} else if (newHost != oldHost) {
//host would be the same, but different state?
sa.setHostCard(newHost);
}
copy.setOverridingAbility(sa);
} }
// 2015-03-07 Removing the ID copying which makes copied triggers Identical to each other when removing if (!lki) {
//copy.setID(this.getId()); copy.setId(nextId());
copy.setMode(this.getMode()); }
copy.setTriggerPhases(this.validPhases);
if (validPhases != null) {
copy.setTriggerPhases(Lists.newArrayList(validPhases));
}
copy.setActiveZone(validHostZones); copy.setActiveZone(validHostZones);
copy.setTemporary(isTemporary()); copy.setTemporary(isTemporary());
return copy; return copy;
@@ -572,4 +564,14 @@ public abstract class Trigger extends TriggerReplacementBase {
{ {
this.numberTurnActivations = 0; this.numberTurnActivations = 0;
} }
/** {@inheritDoc} */
@Override
public final Object clone() {
try {
return super.clone();
} catch (final Exception ex) {
throw new RuntimeException("Trigger : clone() error, " + ex);
}
}
} }

View File

@@ -86,11 +86,9 @@ public enum TriggerType {
Untaps(TriggerUntaps.class), Untaps(TriggerUntaps.class),
Vote(TriggerVote.class); Vote(TriggerVote.class);
private final Class<? extends Trigger> classTrigger;
private final Constructor<? extends Trigger> constructor; private final Constructor<? extends Trigger> constructor;
private TriggerType(Class<? extends Trigger> clasz) { private TriggerType(Class<? extends Trigger> clasz) {
classTrigger = clasz;
constructor = findConstructor(clasz); constructor = findConstructor(clasz);
} }
@@ -123,16 +121,6 @@ public enum TriggerType {
throw new RuntimeException("Element " + value + " not found in TriggerType enum"); throw new RuntimeException("Element " + value + " not found in TriggerType enum");
} }
public static TriggerType getTypeFor(Trigger t) {
final Class<? extends Trigger> cls = t.getClass();
for (final TriggerType v : TriggerType.values()) {
if (v.classTrigger.equals(cls)) {
return v;
}
}
return null;
}
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
* @param mapParams * @param mapParams

View File

@@ -1,10 +1,8 @@
Name:Clifftop Retreat Name:Clifftop Retreat
ManaCost:no cost ManaCost:no cost
Types:Land Types:Land
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | ReplaceWith$ LandTapped | Description$ CARDNAME enters the battlefield tapped unless you control a Mountain or a Plains. K:ETBReplacement:Other:LandTapped
SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionCheckSVar$ ETBCheckSVar | ConditionSVarCompare$ EQ0 | References$ ETBCheckSVar | SubAbility$ MoveToPlay SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionPresent$ Mountain.YouCtrl,Plains.YouCtrl | ConditionCompare$ EQ0 | SpellDescription$ CARDNAME enters the battlefield tapped unless you control a Mountain or a Plains.
SVar:MoveToPlay:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Battlefield | Defined$ ReplacedCard
SVar:ETBCheckSVar:Count$Valid Mountain.YouCtrl,Plains.YouCtrl
A:AB$ Mana | Cost$ T | Produced$ R | SpellDescription$ Add {R} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ R | SpellDescription$ Add {R} to your mana pool.
A:AB$ Mana | Cost$ T | Produced$ W | SpellDescription$ Add {W} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ W | SpellDescription$ Add {W} to your mana pool.
SVar:Picture:http://www.wizards.com/global/images/magic/general/clifftop_retreat.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/clifftop_retreat.jpg

View File

@@ -1,10 +1,8 @@
Name:Dragonskull Summit Name:Dragonskull Summit
ManaCost:no cost ManaCost:no cost
Types:Land Types:Land
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | ReplaceWith$ LandTapped | Description$ CARDNAME enters the battlefield tapped unless you control a Swamp or a Mountain. K:ETBReplacement:Other:LandTapped
SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionCheckSVar$ ETBCheckSVar | ConditionSVarCompare$ EQ0 | References$ ETBCheckSVar | SubAbility$ MoveToPlay SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionPresent$ Swamp.YouCtrl,Mountain.YouCtrl | ConditionCompare$ EQ0 | SpellDescription$ CARDNAME enters the battlefield tapped unless you control a Swamp or a Mountain.
SVar:MoveToPlay:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Battlefield | Defined$ ReplacedCard
SVar:ETBCheckSVar:Count$Valid Swamp.YouCtrl,Mountain.YouCtrl
A:AB$ Mana | Cost$ T | Produced$ B | SpellDescription$ Add {B} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ B | SpellDescription$ Add {B} to your mana pool.
A:AB$ Mana | Cost$ T | Produced$ R | SpellDescription$ Add {R} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ R | SpellDescription$ Add {R} to your mana pool.
SVar:Picture:http://www.wizards.com/global/images/magic/general/dragonskull_summit.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/dragonskull_summit.jpg

View File

@@ -1,10 +1,8 @@
Name:Drowned Catacomb Name:Drowned Catacomb
ManaCost:no cost ManaCost:no cost
Types:Land Types:Land
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | ReplaceWith$ LandTapped | Description$ CARDNAME enters the battlefield tapped unless you control an Island or a Swamp. K:ETBReplacement:Other:LandTapped
SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionCheckSVar$ ETBCheckSVar | ConditionSVarCompare$ EQ0 | References$ ETBCheckSVar | SubAbility$ MoveToPlay SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionPresent$ Island.YouCtrl,Swamp.YouCtrl | ConditionCompare$ EQ0 | SpellDescription$ CARDNAME enters the battlefield tapped unless you control an Island or a Swamp.
SVar:MoveToPlay:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Battlefield | Defined$ ReplacedCard
SVar:ETBCheckSVar:Count$Valid Island.YouCtrl,Swamp.YouCtrl
A:AB$ Mana | Cost$ T | Produced$ U | SpellDescription$ Add {U} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ U | SpellDescription$ Add {U} to your mana pool.
A:AB$ Mana | Cost$ T | Produced$ B | SpellDescription$ Add {B} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ B | SpellDescription$ Add {B} to your mana pool.
SVar:Picture:http://www.wizards.com/global/images/magic/general/drowned_catacomb.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/drowned_catacomb.jpg

View File

@@ -1,10 +1,8 @@
Name:Glacial Fortress Name:Glacial Fortress
ManaCost:no cost ManaCost:no cost
Types:Land Types:Land
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | ReplaceWith$ LandTapped | Description$ CARDNAME enters the battlefield tapped unless you control a Plains or an Island. K:ETBReplacement:Other:LandTapped
SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionCheckSVar$ ETBCheckSVar | ConditionSVarCompare$ EQ0 | References$ ETBCheckSVar | SubAbility$ MoveToPlay SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionPresent$ Plains.YouCtrl,Island.YouCtrl | ConditionCompare$ EQ0 | SpellDescription$ CARDNAME enters the battlefield tapped unless you control a Plains or an Island.
SVar:MoveToPlay:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Battlefield | Defined$ ReplacedCard
SVar:ETBCheckSVar:Count$Valid Island.YouCtrl,Plains.YouCtrl
A:AB$ Mana | Cost$ T | Produced$ W | SpellDescription$ Add {W} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ W | SpellDescription$ Add {W} to your mana pool.
A:AB$ Mana | Cost$ T | Produced$ U | SpellDescription$ Add {U} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ U | SpellDescription$ Add {U} to your mana pool.
SVar:Picture:http://www.wizards.com/global/images/magic/general/glacial_fortress.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/glacial_fortress.jpg

View File

@@ -1,10 +1,8 @@
Name:Hinterland Harbor Name:Hinterland Harbor
ManaCost:no cost ManaCost:no cost
Types:Land Types:Land
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | ReplaceWith$ LandTapped | Description$ CARDNAME enters the battlefield tapped unless you control a Forest or an Island. K:ETBReplacement:Other:LandTapped
SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionCheckSVar$ ETBCheckSVar | ConditionSVarCompare$ EQ0 | References$ ETBCheckSVar | SubAbility$ MoveToPlay SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionPresent$ Forest.YouCtrl,Island.YouCtrl | ConditionCompare$ EQ0 | SpellDescription$ CARDNAME enters the battlefield tapped unless you control a Forest or an Island.
SVar:MoveToPlay:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Battlefield | Defined$ ReplacedCard
SVar:ETBCheckSVar:Count$Valid Island.YouCtrl,Forest.YouCtrl
A:AB$ Mana | Cost$ T | Produced$ G | SpellDescription$ Add {G} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ G | SpellDescription$ Add {G} to your mana pool.
A:AB$ Mana | Cost$ T | Produced$ U | SpellDescription$ Add {U} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ U | SpellDescription$ Add {U} to your mana pool.
SVar:Picture:http://www.wizards.com/global/images/magic/general/hinterland_harbor.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/hinterland_harbor.jpg

View File

@@ -1,10 +1,8 @@
Name:Isolated Chapel Name:Isolated Chapel
ManaCost:no cost ManaCost:no cost
Types:Land Types:Land
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | ReplaceWith$ LandTapped | Description$ CARDNAME enters the battlefield tapped unless you control a Plains or a Swamp. K:ETBReplacement:Other:LandTapped
SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionCheckSVar$ ETBCheckSVar | ConditionSVarCompare$ EQ0 | References$ ETBCheckSVar | SubAbility$ MoveToPlay SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionPresent$ Plains.YouCtrl,Swamp.YouCtrl | ConditionCompare$ EQ0 | SpellDescription$ CARDNAME enters the battlefield tapped unless you control a Plains or a Swamp.
SVar:MoveToPlay:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Battlefield | Defined$ ReplacedCard
SVar:ETBCheckSVar:Count$Valid Plains.YouCtrl,Swamp.YouCtrl
A:AB$ Mana | Cost$ T | Produced$ W | SpellDescription$ Add {W} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ W | SpellDescription$ Add {W} to your mana pool.
A:AB$ Mana | Cost$ T | Produced$ B | SpellDescription$ Add {B} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ B | SpellDescription$ Add {B} to your mana pool.
SVar:Picture:http://www.wizards.com/global/images/magic/general/isolated_chapel.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/isolated_chapel.jpg

View File

@@ -1,10 +1,8 @@
Name:Rootbound Crag Name:Rootbound Crag
ManaCost:no cost ManaCost:no cost
Types:Land Types:Land
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | ReplaceWith$ LandTapped | Description$ CARDNAME enters the battlefield tapped unless you control a Mountain or a Forest. K:ETBReplacement:Other:LandTapped
SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionCheckSVar$ ETBCheckSVar | ConditionSVarCompare$ EQ0 | References$ ETBCheckSVar | SubAbility$ MoveToPlay SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionPresent$ Mountain.YouCtrl,Forest.YouCtrl | ConditionCompare$ EQ0 | SpellDescription$ CARDNAME enters the battlefield tapped unless you control a Mountain or a Forest.
SVar:MoveToPlay:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Battlefield | Defined$ ReplacedCard
SVar:ETBCheckSVar:Count$Valid Mountain.YouCtrl,Forest.YouCtrl
A:AB$ Mana | Cost$ T | Produced$ R | SpellDescription$ Add {R} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ R | SpellDescription$ Add {R} to your mana pool.
A:AB$ Mana | Cost$ T | Produced$ G | SpellDescription$ Add {G} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ G | SpellDescription$ Add {G} to your mana pool.
SVar:Picture:http://www.wizards.com/global/images/magic/general/rootbound_crag.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/rootbound_crag.jpg

View File

@@ -1,10 +1,8 @@
Name:Sulfur Falls Name:Sulfur Falls
ManaCost:no cost ManaCost:no cost
Types:Land Types:Land
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | ReplaceWith$ LandTapped | Description$ CARDNAME enters the battlefield tapped unless you control an Island or a Mountain. K:ETBReplacement:Other:LandTapped
SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionCheckSVar$ ETBCheckSVar | ConditionSVarCompare$ EQ0 | References$ ETBCheckSVar | SubAbility$ MoveToPlay SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionPresent$ Island.YouCtrl,Mountain.YouCtrl | ConditionCompare$ EQ0 | SpellDescription$ CARDNAME enters the battlefield tapped unless you control an Island or a Mountain.
SVar:MoveToPlay:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Battlefield | Defined$ ReplacedCard
SVar:ETBCheckSVar:Count$Valid Mountain.YouCtrl,Island.YouCtrl
A:AB$ Mana | Cost$ T | Produced$ U | SpellDescription$ Add {U} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ U | SpellDescription$ Add {U} to your mana pool.
A:AB$ Mana | Cost$ T | Produced$ R | SpellDescription$ Add {R} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ R | SpellDescription$ Add {R} to your mana pool.
SVar:Picture:http://www.wizards.com/global/images/magic/general/sulfur_falls.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/sulfur_falls.jpg

View File

@@ -1,10 +1,8 @@
Name:Sunpetal Grove Name:Sunpetal Grove
ManaCost:no cost ManaCost:no cost
Types:Land Types:Land
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | ReplaceWith$ LandTapped | Description$ CARDNAME enters the battlefield tapped unless you control a Forest or a Plains. K:ETBReplacement:Other:LandTapped
SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionCheckSVar$ ETBCheckSVar | ConditionSVarCompare$ EQ0 | References$ ETBCheckSVar | SubAbility$ MoveToPlay SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionPresent$ Forest.YouCtrl,Plains.YouCtrl | ConditionCompare$ EQ0 | SpellDescription$ CARDNAME enters the battlefield tapped unless you control a Forest or a Plains.
SVar:MoveToPlay:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Battlefield | Defined$ ReplacedCard
SVar:ETBCheckSVar:Count$Valid Forest.YouCtrl,Plains.YouCtrl
A:AB$ Mana | Cost$ T | Produced$ W | SpellDescription$ Add {W} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ W | SpellDescription$ Add {W} to your mana pool.
A:AB$ Mana | Cost$ T | Produced$ G | SpellDescription$ Add {G} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ G | SpellDescription$ Add {G} to your mana pool.
SVar:Picture:http://www.wizards.com/global/images/magic/general/sunpetal_grove.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/sunpetal_grove.jpg

View File

@@ -1,10 +1,8 @@
Name:Woodland Cemetery Name:Woodland Cemetery
ManaCost:no cost ManaCost:no cost
Types:Land Types:Land
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | ReplaceWith$ LandTapped | Description$ CARDNAME enters the battlefield tapped unless you control a Swamp or a Forest. K:ETBReplacement:Other:LandTapped
SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionCheckSVar$ ETBCheckSVar | ConditionSVarCompare$ EQ0 | References$ ETBCheckSVar | SubAbility$ MoveToPlay SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionPresent$ Swamp.YouCtrl,Forest.YouCtrl | ConditionCompare$ EQ0 | SpellDescription$ CARDNAME enters the battlefield tapped unless you control a Swamp or a Forest.
SVar:MoveToPlay:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Battlefield | Defined$ ReplacedCard
SVar:ETBCheckSVar:Count$Valid Swamp.YouCtrl,Forest.YouCtrl
A:AB$ Mana | Cost$ T | Produced$ B | SpellDescription$ Add {B} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ B | SpellDescription$ Add {B} to your mana pool.
A:AB$ Mana | Cost$ T | Produced$ G | SpellDescription$ Add {G} to your mana pool. A:AB$ Mana | Cost$ T | Produced$ G | SpellDescription$ Add {G} to your mana pool.
SVar:Picture:http://www.wizards.com/global/images/magic/general/woodland_cemetery.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/woodland_cemetery.jpg