Merge remote-tracking branch 'upstream/master' into fix-deck-editor-custom-editions-image-view

This commit is contained in:
leriomaggio
2021-05-31 09:12:32 +01:00
86 changed files with 1020 additions and 227 deletions

View File

@@ -787,7 +787,8 @@ public class PlayerControllerAi extends PlayerController {
case "BetterTgtThanRemembered": case "BetterTgtThanRemembered":
if (source.getRememberedCount() > 0) { if (source.getRememberedCount() > 0) {
Card rem = (Card) source.getFirstRemembered(); Card rem = (Card) source.getFirstRemembered();
if (!rem.isInZone(ZoneType.Battlefield)) { // avoid pumping opponent creature
if (!rem.isInZone(ZoneType.Battlefield) || rem.getController().isOpponentOf(source.getController())) {
return true; return true;
} }
for (Card c : source.getController().getCreaturesInPlay()) { for (Card c : source.getController().getCreaturesInPlay()) {

View File

@@ -227,7 +227,7 @@ public class CharmAi extends SpellAbilityAi {
if (AiPlayDecision.WillPlay == aic.canPlaySa(sub)) { if (AiPlayDecision.WillPlay == aic.canPlaySa(sub)) {
chosenList.add(sub); chosenList.add(sub);
if (chosenList.size() == min) { if (chosenList.size() == min) {
break; // enough choices break; // enough choices
} }
} }
} }

View File

@@ -28,7 +28,6 @@ public class LifeLoseAi extends SpellAbilityAi {
*/ */
@Override @Override
public boolean chkAIDrawback(SpellAbility sa, Player ai) { public boolean chkAIDrawback(SpellAbility sa, Player ai) {
final PlayerCollection tgtPlayers = getPlayers(ai, sa); final PlayerCollection tgtPlayers = getPlayers(ai, sa);
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
@@ -127,6 +126,7 @@ public class LifeLoseAi extends SpellAbilityAi {
} }
final PlayerCollection tgtPlayers = getPlayers(ai, sa); final PlayerCollection tgtPlayers = getPlayers(ai, sa);
// TODO: check against the amount we could obtain when multiple activations are possible
PlayerCollection filteredPlayer = tgtPlayers PlayerCollection filteredPlayer = tgtPlayers
.filter(Predicates.and(PlayerPredicates.isOpponentOf(ai), PlayerPredicates.lifeLessOrEqualTo(amount))); .filter(Predicates.and(PlayerPredicates.isOpponentOf(ai), PlayerPredicates.lifeLessOrEqualTo(amount)));
// killing opponents asap // killing opponents asap

View File

@@ -532,8 +532,7 @@ public abstract class PumpAiBase extends SpellAbilityAi {
protected boolean containsNonCombatKeyword(final List<String> keywords) { protected boolean containsNonCombatKeyword(final List<String> keywords) {
for (final String keyword : keywords) { for (final String keyword : keywords) {
// since most keywords are combat relevant check for those that are // since most keywords are combat relevant check for those that are not
// not
if (keyword.endsWith("This card doesn't untap during your next untap step.") if (keyword.endsWith("This card doesn't untap during your next untap step.")
|| keyword.endsWith("Shroud") || keyword.endsWith("Hexproof")) { || keyword.endsWith("Shroud") || keyword.endsWith("Hexproof")) {
return true; return true;

View File

@@ -194,10 +194,15 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
} catch (NumberFormatException ex) { } catch (NumberFormatException ex) {
String nonNumeric = sortableCollNr.replaceAll("[0-9]", ""); String nonNumeric = sortableCollNr.replaceAll("[0-9]", "");
String onlyNumeric = sortableCollNr.replaceAll("[^0-9]", ""); String onlyNumeric = sortableCollNr.replaceAll("[^0-9]", "");
if (sortableCollNr.startsWith(onlyNumeric)) // e.g. 12a, 37+, 2018f, try {
sortableCollNr = String.format("%05d", Integer.parseInt(onlyNumeric)) + nonNumeric; collNr = Integer.parseInt(onlyNumeric);
} catch (NumberFormatException exon) {
collNr = 0; // this is the case of ONLY-letters collector numbers
}
if ((collNr > 0) && (sortableCollNr.startsWith(onlyNumeric))) // e.g. 12a, 37+, 2018f,
sortableCollNr = String.format("%05d", collNr) + nonNumeric;
else // e.g. WS6, S1 else // e.g. WS6, S1
sortableCollNr = nonNumeric + String.format("%05d", Integer.parseInt(onlyNumeric)); sortableCollNr = nonNumeric + String.format("%05d", collNr);
} }
return sortableCollNr; return sortableCollNr;
} }

View File

@@ -2131,25 +2131,19 @@ public class GameAction {
public void dealDamage(final boolean isCombat, final CardDamageMap damageMap, final CardDamageMap preventMap, public void dealDamage(final boolean isCombat, final CardDamageMap damageMap, final CardDamageMap preventMap,
final GameEntityCounterTable counterTable, final SpellAbility cause) { final GameEntityCounterTable counterTable, final SpellAbility cause) {
CardDamageMap replaceDamageMap = new CardDamageMap(damageMap); // Clear assigned damage if is combat
// Run replacement effect for each entity dealt damage
// TODO: List all possible replacement effects and run them in APNAP order.
// TODO: To handle "Prevented this way" and abilities like "Phantom Nomad", should buffer the replaced SA
// and only run them after all prevention and redirection effects are processed.
for (Map.Entry<GameEntity, Map<Card, Integer>> et : damageMap.columnMap().entrySet()) { for (Map.Entry<GameEntity, Map<Card, Integer>> et : damageMap.columnMap().entrySet()) {
final GameEntity ge = et.getKey(); final GameEntity ge = et.getKey();
if (isCombat && ge instanceof Card) { if (isCombat && ge instanceof Card) {
((Card) ge).clearAssignedDamage(); ((Card) ge).clearAssignedDamage();
} }
for (Map.Entry<Card, Integer> e : et.getValue().entrySet()) {
if (e.getValue() > 0) {
ge.replaceDamage(e.getValue(), e.getKey(), isCombat, replaceDamageMap, preventMap, counterTable, cause);
}
}
} }
// Run replacement effect for each entity dealt damage
game.getReplacementHandler().runReplaceDamage(isCombat, damageMap, preventMap, counterTable, cause);
// Actually deal damage according to replaced damage map // Actually deal damage according to replaced damage map
for (Map.Entry<Card, Map<GameEntity, Integer>> et : replaceDamageMap.rowMap().entrySet()) { for (Map.Entry<Card, Map<GameEntity, Integer>> et : damageMap.rowMap().entrySet()) {
final Card sourceLKI = et.getKey(); final Card sourceLKI = et.getKey();
int sum = 0; int sum = 0;
for (Map.Entry<GameEntity, Integer> e : et.getValue().entrySet()) { for (Map.Entry<GameEntity, Integer> e : et.getValue().entrySet()) {
@@ -2168,9 +2162,8 @@ public class GameAction {
preventMap.triggerPreventDamage(isCombat); preventMap.triggerPreventDamage(isCombat);
preventMap.clear(); preventMap.clear();
replaceDamageMap.triggerDamageDoneOnce(isCombat, game); damageMap.triggerDamageDoneOnce(isCombat, game);
damageMap.clear(); damageMap.clear();
replaceDamageMap.clear();
counterTable.triggerCountersPutAll(game); counterTable.triggerCountersPutAll(game);
counterTable.clear(); counterTable.clear();

View File

@@ -23,13 +23,11 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollection; import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView; import forge.game.card.CardCollectionView;
import forge.game.card.CardDamageMap;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardPredicates; import forge.game.card.CardPredicates;
import forge.game.card.CounterEnumType; import forge.game.card.CounterEnumType;
@@ -67,43 +65,6 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
getView().updateName(this); getView().updateName(this);
} }
// final Iterable<Card> source
public void replaceDamage(final int damage, final Card source, final boolean isCombat,
final CardDamageMap damageMap, final CardDamageMap preventMap, GameEntityCounterTable counterTable, final SpellAbility cause) {
boolean prevention = source.canDamagePrevented(isCombat) && (cause == null || !cause.hasParam("NoPrevention"));
// Replacement effects
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
repParams.put(AbilityKey.DamageSource, source);
repParams.put(AbilityKey.DamageAmount, damage);
repParams.put(AbilityKey.IsCombat, isCombat);
repParams.put(AbilityKey.NoPreventDamage, !prevention);
repParams.put(AbilityKey.DamageMap, damageMap);
repParams.put(AbilityKey.PreventMap, preventMap);
repParams.put(AbilityKey.CounterTable, counterTable);
if (cause != null) {
repParams.put(AbilityKey.Cause, cause);
}
switch (getGame().getReplacementHandler().run(ReplacementType.DamageDone, repParams)) {
case NotReplaced:
break;
case Updated:
int newDamage = (int) repParams.get(AbilityKey.DamageAmount);
GameEntity newTarget = (GameEntity) repParams.get(AbilityKey.Affected);
// check if this is still the affected card or player
if (this.equals(newTarget)) {
damageMap.put(source, this, newDamage - damage);
} else {
damageMap.remove(source, this);
damageMap.put(source, newTarget, newDamage);
}
break;
default:
damageMap.remove(source, this);
}
}
// This function handles damage after replacement and prevention effects are applied // This function handles damage after replacement and prevention effects are applied
public abstract int addDamageAfterPrevention(final int damage, final Card source, final boolean isCombat, GameEntityCounterTable counterTable); public abstract int addDamageAfterPrevention(final int damage, final Card source, final boolean isCombat, GameEntityCounterTable counterTable);

View File

@@ -96,12 +96,14 @@ public enum AbilityKey {
PayingMana("PayingMana"), PayingMana("PayingMana"),
Phase("Phase"), Phase("Phase"),
Player("Player"), Player("Player"),
PreventedAmount("PreventedAmount"),
PreventMap("PreventMap"), PreventMap("PreventMap"),
Prevention("Prevention"), Prevention("Prevention"),
Produced("Produced"), Produced("Produced"),
Regeneration("Regeneration"), Regeneration("Regeneration"),
ReplacementEffect("ReplacementEffect"), ReplacementEffect("ReplacementEffect"),
ReplacementResult("ReplacementResult"), ReplacementResult("ReplacementResult"),
ReplacementResultMap("ReplacementResultMap"),
Result("Result"), Result("Result"),
Scheme("Scheme"), Scheme("Scheme"),
Source("Source"), Source("Source"),

View File

@@ -16,13 +16,11 @@ public class AddTurnEffect extends SpellAbilityEffect {
@Override @Override
protected String getStackDescription(SpellAbility sa) { protected String getStackDescription(SpellAbility sa) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
final int numTurns = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("NumTurns"), sa); final int numTurns = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("NumTurns"), sa);
List<Player> tgtPlayers = getTargetPlayers(sa); List<Player> tgtPlayers = getTargetPlayers(sa);
for (final Player player : tgtPlayers) { for (final Player player : tgtPlayers) {
sb.append(player).append(" "); sb.append(player).append(" ");
} }

View File

@@ -31,13 +31,12 @@ public class ManaEffect extends SpellAbilityEffect {
@Override @Override
public void resolve(SpellAbility sa) { public void resolve(SpellAbility sa) {
final Card card = sa.getHostCard(); final Card card = sa.getHostCard();
AbilityManaPart abMana = sa.getManaPart(); AbilityManaPart abMana = sa.getManaPart();
final List<Player> tgtPlayers = getTargetPlayers(sa);
// Spells are not undoable // Spells are not undoable
sa.setUndoable(sa.isAbility() && sa.isUndoable()); sa.setUndoable(sa.isAbility() && sa.isUndoable() && tgtPlayers.size() < 2);
final List<Player> tgtPlayers = getTargetPlayers(sa);
final boolean optional = sa.hasParam("Optional"); final boolean optional = sa.hasParam("Optional");
final Game game = sa.getActivatingPlayer().getGame(); final Game game = sa.getActivatingPlayer().getGame();

View File

@@ -5,17 +5,12 @@ import java.util.Map;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import forge.game.Game; import forge.game.Game;
import forge.game.GameEntity;
import forge.game.GameLogEntryType;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardDamageMap;
import forge.game.replacement.ReplacementResult; import forge.game.replacement.ReplacementResult;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.util.TextUtil;
/** /**
* This class handles two kinds of prevention effect: * This class handles two kinds of prevention effect:
@@ -37,8 +32,6 @@ public class ReplaceDamageEffect extends SpellAbilityEffect {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Map<AbilityKey, Object> originalParams = (Map<AbilityKey, Object>) sa.getReplacingObject(AbilityKey.OriginalParams); Map<AbilityKey, Object> originalParams = (Map<AbilityKey, Object>) sa.getReplacingObject(AbilityKey.OriginalParams);
Map<AbilityKey, Object> params = AbilityKey.newMap(originalParams);
Integer dmg = (Integer) sa.getReplacingObject(AbilityKey.DamageAmount); Integer dmg = (Integer) sa.getReplacingObject(AbilityKey.DamageAmount);
String varValue = sa.getParamOrDefault("Amount", "1"); String varValue = sa.getParamOrDefault("Amount", "1");
@@ -59,21 +52,6 @@ public class ReplaceDamageEffect extends SpellAbilityEffect {
} }
// Set PreventedDamage SVar // Set PreventedDamage SVar
card.setSVar("PreventedDamage", "Number$" + n); card.setSVar("PreventedDamage", "Number$" + n);
Card sourceLKI = (Card) sa.getReplacingObject(AbilityKey.Source);
GameEntity target = (GameEntity) sa.getReplacingObject(AbilityKey.Target);
// Set prevent map entry
CardDamageMap preventMap = (CardDamageMap) originalParams.get(AbilityKey.PreventMap);
preventMap.put(sourceLKI, target, n);
// Following codes are commented out since DamagePrevented trigger is currently not used by any Card.
// final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
// runParams.put(AbilityKey.DamageTarget, target);
// runParams.put(AbilityKey.DamageAmount, dmg);
// runParams.put(AbilityKey.DamageSource, sourceLKI);
// runParams.put(AbilityKey.IsCombatDamage, originalParams.get(AbilityKey.IsCombat));
// game.getTriggerHandler().runTrigger(TriggerType.DamagePrevented, runParams, false);
} }
// no damage for original target anymore // no damage for original target anymore
@@ -81,33 +59,8 @@ public class ReplaceDamageEffect extends SpellAbilityEffect {
originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Replaced); originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Replaced);
return; return;
} }
params.put(AbilityKey.DamageAmount, dmg); originalParams.put(AbilityKey.DamageAmount, dmg);
originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
// need to log Updated events there, or the log is wrong order
String message = sa.getReplacementEffect().toString();
if ( !StringUtils.isEmpty(message)) {
message = TextUtil.fastReplace(message, "CARDNAME", card.getName());
game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message);
}
//try to call replacementHandler with new Params
final ReplacementType event = sa.getReplacementEffect().getMode();
ReplacementResult result = game.getReplacementHandler().run(event, params);
switch (result) {
case NotReplaced:
case Updated: {
for (Map.Entry<AbilityKey, Object> e : params.entrySet()) {
originalParams.put(e.getKey(), e.getValue());
}
// effect was updated
originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
break;
}
default:
// effect was replaced with something else
originalParams.put(AbilityKey.ReplacementResult, result);
break;
}
} }
} }

View File

@@ -65,6 +65,14 @@ public class ReplaceEffect extends SpellAbilityEffect {
params.put(AbilityKey.EffectOnly, true); params.put(AbilityKey.EffectOnly, true);
} }
if (retype == ReplacementType.DamageDone) {
for (Map.Entry<AbilityKey, Object> e : params.entrySet()) {
originalParams.put(e.getKey(), e.getValue());
}
originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
return;
}
// need to log Updated events there, or the log is wrong order // need to log Updated events there, or the log is wrong order
String message = sa.getReplacementEffect().toString(); String message = sa.getReplacementEffect().toString();
if ( !StringUtils.isEmpty(message)) { if ( !StringUtils.isEmpty(message)) {

View File

@@ -7,15 +7,12 @@ import org.apache.commons.lang3.StringUtils;
import forge.game.Game; import forge.game.Game;
import forge.game.GameEntity; import forge.game.GameEntity;
import forge.game.GameEntityCounterTable;
import forge.game.GameObject; import forge.game.GameObject;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardDamageMap;
import forge.game.replacement.ReplacementResult; import forge.game.replacement.ReplacementResult;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
public class ReplaceSplitDamageEffect extends SpellAbilityEffect { public class ReplaceSplitDamageEffect extends SpellAbilityEffect {
@@ -30,19 +27,13 @@ public class ReplaceSplitDamageEffect extends SpellAbilityEffect {
return; return;
} }
final ReplacementType event = sa.getReplacementEffect().getMode();
String varValue = sa.getParamOrDefault("VarName", "1"); String varValue = sa.getParamOrDefault("VarName", "1");
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Map<AbilityKey, Object> originalParams = (Map<AbilityKey , Object>) sa.getReplacingObject(AbilityKey.OriginalParams); Map<AbilityKey, Object> originalParams = (Map<AbilityKey , Object>) sa.getReplacingObject(AbilityKey.OriginalParams);
Map<AbilityKey, Object> params = AbilityKey.newMap(originalParams);
Integer dmg = (Integer) sa.getReplacingObject(AbilityKey.DamageAmount); Integer dmg = (Integer) sa.getReplacingObject(AbilityKey.DamageAmount);
int prevent = AbilityUtils.calculateAmount(card, varValue, sa); int prevent = AbilityUtils.calculateAmount(card, varValue, sa);
List<GameObject> list = AbilityUtils.getDefinedObjects(card, sa.getParam("DamageTarget"), sa); List<GameObject> list = AbilityUtils.getDefinedObjects(card, sa.getParam("DamageTarget"), sa);
if (prevent > 0 && list.size() > 0 && list.get(0) instanceof GameEntity) { if (prevent > 0 && list.size() > 0 && list.get(0) instanceof GameEntity) {
@@ -56,18 +47,10 @@ public class ReplaceSplitDamageEffect extends SpellAbilityEffect {
sa.setSVar(varValue, "Number$" + prevent); sa.setSVar(varValue, "Number$" + prevent);
card.updateAbilityTextForView(); card.updateAbilityTextForView();
} }
Card sourceLKI = (Card) sa.getReplacingObject(AbilityKey.Source);
GameEntity target = (GameEntity) sa.getReplacingObject(AbilityKey.Target);
GameEntity obj = (GameEntity) list.get(0); GameEntity obj = (GameEntity) list.get(0);
boolean isCombat = (Boolean) originalParams.get(AbilityKey.IsCombat); originalParams.put(AbilityKey.Affected, obj);
CardDamageMap damageMap = (CardDamageMap) originalParams.get(AbilityKey.DamageMap); originalParams.put(AbilityKey.DamageAmount, n);
CardDamageMap preventMap = (CardDamageMap) originalParams.get(AbilityKey.PreventMap);
GameEntityCounterTable counterTable = (GameEntityCounterTable) originalParams.get(AbilityKey.CounterTable);
SpellAbility cause = (SpellAbility) originalParams.get(AbilityKey.Cause);
damageMap.put(sourceLKI, obj, n);
obj.replaceDamage(n, sourceLKI, isCombat, damageMap, preventMap, counterTable, cause);
} }
// no damage for original target anymore // no damage for original target anymore
@@ -75,25 +58,7 @@ public class ReplaceSplitDamageEffect extends SpellAbilityEffect {
originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Replaced); originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Replaced);
return; return;
} }
params.put(AbilityKey.DamageAmount, dmg); originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
//try to call replacementHandler with new Params
ReplacementResult result = game.getReplacementHandler().run(event, params);
switch (result) {
case NotReplaced:
case Updated: {
for (Map.Entry<AbilityKey, Object> e : params.entrySet()) {
originalParams.put(e.getKey(), e.getValue());
}
// effect was updated
originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
break;
}
default:
// effect was replaced with something else
originalParams.put(AbilityKey.ReplacementResult, result);
break;
}
} }
} }

View File

@@ -67,4 +67,3 @@ public class SkipTurnEffect extends SpellAbilityEffect {
} }
} }
} }

View File

@@ -3232,8 +3232,17 @@ public class CardFactoryUtil {
if (keyword.startsWith("Affinity")) { if (keyword.startsWith("Affinity")) {
final String[] k = keyword.split(":"); final String[] k = keyword.split(":");
final String t = k[1]; final String t = k[1];
String d = "";
if (k.length > 2) {
final StringBuilder s = new StringBuilder();
s.append(k[2]).append("s");
d = s.toString();
}
String desc = "Artifact".equals(t) ? "artifacts" : CardType.getPluralType(t); String desc = "Artifact".equals(t) ? "artifacts" : CardType.getPluralType(t);
if (!d.isEmpty()) {
desc = d;
}
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ AffinityX | EffectZone$ All"); sb.append("Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ AffinityX | EffectZone$ All");
sb.append("| Description$ Affinity for ").append(desc); sb.append("| Description$ Affinity for ").append(desc);

View File

@@ -18,7 +18,7 @@ public enum Keyword {
UNDEFINED("", SimpleKeyword.class, false, ""), UNDEFINED("", SimpleKeyword.class, false, ""),
ABSORB("Absorb", KeywordWithAmount.class, false, "If a source would deal damage to this creature, prevent %d of that damage."), ABSORB("Absorb", KeywordWithAmount.class, false, "If a source would deal damage to this creature, prevent %d of that damage."),
ADAPT("Adapt", KeywordWithCostAndAmount.class, false, "If this creature has no +1/+1 counters on it, put {%2$d:+1/+1 counter} on it."), ADAPT("Adapt", KeywordWithCostAndAmount.class, false, "If this creature has no +1/+1 counters on it, put {%2$d:+1/+1 counter} on it."),
AFFINITY("Affinity", KeywordWithType.class, false, "This spell costs you {1} less to cast for each %s you control."), AFFINITY("Affinity", KeywordWithType.class, false, "This spell costs {1} less to cast for each %s you control."),
AFFLICT("Afflict", KeywordWithAmount.class, false, "Whenever this creature becomes blocked, defending player loses %d life."), AFFLICT("Afflict", KeywordWithAmount.class, false, "Whenever this creature becomes blocked, defending player loses %d life."),
AFTERLIFE("Afterlife", KeywordWithAmount.class, false, "When this creature dies, create {%1$d:1/1 white and black Spirit creature token} with flying."), AFTERLIFE("Afterlife", KeywordWithAmount.class, false, "When this creature dies, create {%1$d:1/1 white and black Spirit creature token} with flying."),
AFTERMATH("Aftermath", SimpleKeyword.class, false, "Cast this spell only from your graveyard. Then exile it."), AFTERMATH("Aftermath", SimpleKeyword.class, false, "Cast this spell only from your graveyard. Then exile it."),

View File

@@ -11,6 +11,9 @@ public class KeywordWithType extends KeywordInstance<KeywordWithType> {
type = details.toLowerCase(); type = details.toLowerCase();
} else if (details.contains(":")) { } else if (details.contains(":")) {
type = details.split(":")[0]; type = details.split(":")[0];
if (this.toString().startsWith("Affinity")) {
type = details.split(":")[1];
}
} else { } else {
type = details; type = details;
} }

View File

@@ -38,6 +38,9 @@ public class ReplaceProduceMana extends ReplacementEffect {
if (!matchesValidParam("ValidPlayer", runParams.get(AbilityKey.Player))) { if (!matchesValidParam("ValidPlayer", runParams.get(AbilityKey.Player))) {
return false; return false;
} }
if (!matchesValidParam("ValidActivator", runParams.get(AbilityKey.Activator))) {
return false;
}
if (!matchesValidParam("ValidAbility", runParams.get(AbilityKey.AbilityMana))) { if (!matchesValidParam("ValidAbility", runParams.get(AbilityKey.AbilityMana))) {
return false; return false;
} }
@@ -58,7 +61,6 @@ public class ReplaceProduceMana extends ReplacementEffect {
return true; return true;
} }
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) { public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
sa.setReplacingObject(AbilityKey.Mana, runParams.get(AbilityKey.Mana)); sa.setReplacingObject(AbilityKey.Mana, runParams.get(AbilityKey.Mana));
} }

View File

@@ -17,7 +17,10 @@
*/ */
package forge.game.replacement; package forge.game.replacement;
import java.util.ArrayList;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -30,6 +33,7 @@ import com.google.common.collect.Sets;
import forge.game.CardTraitBase; import forge.game.CardTraitBase;
import forge.game.Game; import forge.game.Game;
import forge.game.GameEntity; import forge.game.GameEntity;
import forge.game.GameEntityCounterTable;
import forge.game.GameLogEntryType; import forge.game.GameLogEntryType;
import forge.game.IHasSVars; import forge.game.IHasSVars;
import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityFactory;
@@ -45,6 +49,8 @@ import forge.game.card.CardUtil;
import forge.game.keyword.KeywordInterface; import forge.game.keyword.KeywordInterface;
import forge.game.keyword.KeywordsChange; import forge.game.keyword.KeywordsChange;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.player.PlayerCollection;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.Zone; import forge.game.zone.Zone;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
@@ -58,6 +64,10 @@ public class ReplacementHandler {
private final Game game; private final Game game;
private Set<ReplacementEffect> hasRun = Sets.newHashSet(); private Set<ReplacementEffect> hasRun = Sets.newHashSet();
// List of all replacement effect candidates for DamageDone event, in APNAP order
private final List<Map<ReplacementEffect, List<Map<AbilityKey, Object>>>> replaceDamageList = new ArrayList<>();
/** /**
* ReplacementHandler. * ReplacementHandler.
* @param gameState * @param gameState
@@ -281,24 +291,6 @@ public class ReplacementHandler {
return res; return res;
} }
private void putPreventMapEntry(final Map<AbilityKey, Object> runParams) {
Card sourceLKI = (Card) runParams.get(AbilityKey.DamageSource);
GameEntity target = (GameEntity) runParams.get(AbilityKey.Affected);
Integer damage = (Integer) runParams.get(AbilityKey.DamageAmount);
// Set prevent map entry
CardDamageMap preventMap = (CardDamageMap) runParams.get(AbilityKey.PreventMap);
preventMap.put(sourceLKI, target, damage);
// Following codes are commented out since DamagePrevented trigger is currently not used by any Card.
// final Map<AbilityKey, Object> trigParams = AbilityKey.newMap();
// trigParams.put(AbilityKey.DamageTarget, target);
// trigParams.put(AbilityKey.DamageAmount, damage);
// trigParams.put(AbilityKey.DamageSource, sourceLKI);
// trigParams.put(AbilityKey.IsCombatDamage, runParams.get(AbilityKey.IsCombat));
// game.getTriggerHandler().runTrigger(TriggerType.DamagePrevented, trigParams, false);
}
/** /**
* *
* Runs a single replacement effect. * Runs a single replacement effect.
@@ -368,14 +360,21 @@ public class ReplacementHandler {
} }
} }
if (mapParams.containsKey("Prevent") && mapParams.get("Prevent").equals("True")) { boolean isPrevent = mapParams.containsKey("Prevent") && mapParams.get("Prevent").equals("True");
if (replacementEffect.getMode() == ReplacementType.DamageDone) { if (isPrevent || mapParams.containsKey("PreventionEffect")) {
if (Boolean.TRUE.equals(runParams.get(AbilityKey.NoPreventDamage))) { if (Boolean.TRUE.equals(runParams.get(AbilityKey.NoPreventDamage))) {
return ReplacementResult.NotReplaced; // If can't prevent damage, result is not replaced
// But still put "prevented" amount for buffered SA
if (mapParams.containsKey("AlwaysReplace")) {
runParams.put(AbilityKey.PreventedAmount, runParams.get(AbilityKey.DamageAmount));
} else {
runParams.put(AbilityKey.PreventedAmount, 0);
} }
putPreventMapEntry(runParams); return ReplacementResult.NotReplaced;
}
if (isPrevent) {
return ReplacementResult.Prevented; // Nothing should replace the event.
} }
return ReplacementResult.Prevented; // Nothing should replace the event.
} }
if (mapParams.containsKey("Skip")) { if (mapParams.containsKey("Skip")) {
@@ -384,25 +383,19 @@ public class ReplacementHandler {
} }
} }
boolean cantPreventDamage = (replacementEffect.getMode() == ReplacementType.DamageDone
&& mapParams.containsKey("PreventionEffect")
&& Boolean.TRUE.equals(runParams.get(AbilityKey.NoPreventDamage)));
Player player = host.getController(); Player player = host.getController();
if (!cantPreventDamage || mapParams.containsKey("AlwaysReplace")) { if (effectSA != null) {
player.getController().playSpellAbilityNoStack(effectSA, true); ApiType apiType = effectSA.getApi();
if (replacementEffect.getMode() == ReplacementType.DamageDone if (replacementEffect.getMode() != ReplacementType.DamageDone ||
&& effectSA.getApi() != ApiType.ReplaceDamage && !cantPreventDamage) { (apiType == ApiType.ReplaceDamage || apiType == ApiType.ReplaceSplitDamage || apiType == ApiType.ReplaceEffect)) {
putPreventMapEntry(runParams); player.getController().playSpellAbilityNoStack(effectSA, true);
} else {
// The SA if buffered, but replacement result should be set to Replaced
runParams.put(AbilityKey.ReplacementResult, ReplacementResult.Replaced);
} }
} }
// If can't prevent damage, result is not replaced
if (cantPreventDamage) {
return ReplacementResult.NotReplaced;
}
// if the spellability is a replace effect then its some new logic // if the spellability is a replace effect then its some new logic
// if ReplacementResult is set in run params use that instead // if ReplacementResult is set in run params use that instead
if (runParams.containsKey(AbilityKey.ReplacementResult)) { if (runParams.containsKey(AbilityKey.ReplacementResult)) {
@@ -412,6 +405,322 @@ public class ReplacementHandler {
return ReplacementResult.Replaced; return ReplacementResult.Replaced;
} }
private void getPossibleReplaceDamageList(PlayerCollection players, final boolean isCombat, final CardDamageMap damageMap, final SpellAbility cause) {
for (Map.Entry<GameEntity, Map<Card, Integer>> et : damageMap.columnMap().entrySet()) {
final GameEntity target = et.getKey();
int playerIndex = (target instanceof Player ? players.indexOf(((Player) target)) :
players.indexOf(((Card) target).getController()));
Map<ReplacementEffect, List<Map<AbilityKey, Object>>> replaceCandidateMap = replaceDamageList.get(playerIndex);
for (Map.Entry<Card, Integer> e : et.getValue().entrySet()) {
Card source = e.getKey();
Integer damage = e.getValue();
if (damage > 0) {
boolean prevention = source.canDamagePrevented(isCombat) &&
(cause == null || !cause.hasParam("NoPrevention"));
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(target);
repParams.put(AbilityKey.DamageSource, source);
repParams.put(AbilityKey.DamageAmount, damage);
repParams.put(AbilityKey.IsCombat, isCombat);
repParams.put(AbilityKey.NoPreventDamage, !prevention);
if (cause != null) {
repParams.put(AbilityKey.Cause, cause);
}
List<ReplacementEffect> reList = getReplacementList(ReplacementType.DamageDone, repParams, ReplacementLayer.Other);
for (ReplacementEffect re : reList) {
if (!replaceCandidateMap.containsKey(re)) {
replaceCandidateMap.put(re, new ArrayList<>());
}
List<Map<AbilityKey, Object>> runParamList = replaceCandidateMap.get(re);
runParamList.add(repParams);
}
}
}
}
}
private void runSingleReplaceDamageEffect(ReplacementEffect re, Map<AbilityKey, Object> runParams, Map<ReplacementEffect, List<Map<AbilityKey, Object>>> replaceCandidateMap,
Map<ReplacementEffect, List<Map<AbilityKey, Object>>> executedDamageMap, Player decider, final CardDamageMap damageMap, final CardDamageMap preventMap) {
List<Map<AbilityKey, Object>> executedParamList = executedDamageMap.get(re);
ApiType apiType = re.getOverridingAbility() != null ? re.getOverridingAbility().getApi() : null;
Card source = (Card) runParams.get(AbilityKey.DamageSource);
GameEntity target = (GameEntity) runParams.get(AbilityKey.Affected);
int damage = (int) runParams.get(AbilityKey.DamageAmount);
Map<String, String> mapParams = re.getMapParams();
ReplacementResult res = executeReplacement(runParams, re, decider, game);
GameEntity newTarget = (GameEntity) runParams.get(AbilityKey.Affected);
int newDamage = (int) runParams.get(AbilityKey.DamageAmount);
// ReplaceSplitDamage will split the damage event into two event, so need to create run params for old event
// (original run params is changed for new event)
Map<AbilityKey, Object> oldParams = null;
if (res != ReplacementResult.NotReplaced) {
// Remove this event from other possible replacers
Iterator<Map.Entry<ReplacementEffect, List<Map<AbilityKey, Object>>>> itr = replaceCandidateMap.entrySet().iterator();
while (itr.hasNext()) {
Map.Entry<ReplacementEffect, List<Map<AbilityKey, Object>>> entry = itr.next();
if (entry.getKey() == re) continue;
if (entry.getValue().contains(runParams)) {
entry.getValue().remove(runParams);
if (entry.getValue().isEmpty()) {
itr.remove();
}
}
}
// Add updated event to possible replacers
if (res == ReplacementResult.Updated || apiType == ApiType.ReplaceSplitDamage) {
Map<ReplacementEffect, List<Map<AbilityKey, Object>>> newReplaceCandidateMap = replaceCandidateMap;
if (!target.equals(newTarget)) {
PlayerCollection players = game.getPlayersInTurnOrder();
int playerIndex = (newTarget instanceof Player ? players.indexOf(((Player) newTarget)) :
players.indexOf(((Card) newTarget).getController()));
newReplaceCandidateMap = replaceDamageList.get(playerIndex);
}
List<ReplacementEffect> reList = getReplacementList(ReplacementType.DamageDone, runParams, ReplacementLayer.Other);
for (ReplacementEffect newRE : reList) {
// Skip if this has already been executed by given replacement effect
if (executedDamageMap.containsKey(newRE) && executedDamageMap.get(newRE).contains(runParams)) {
continue;
}
if (!newReplaceCandidateMap.containsKey(newRE)) {
newReplaceCandidateMap.put(newRE, new ArrayList<>());
}
List<Map<AbilityKey, Object>> runParamList = newReplaceCandidateMap.get(newRE);
runParamList.add(runParams);
}
}
// Add old updated event too for ReplaceSplitDamage
if (apiType == ApiType.ReplaceSplitDamage && res == ReplacementResult.Updated) {
oldParams = AbilityKey.newMap(runParams);
oldParams.put(AbilityKey.Affected, target);
oldParams.put(AbilityKey.DamageAmount, damage - newDamage);
List<ReplacementEffect> reList = getReplacementList(ReplacementType.DamageDone, oldParams, ReplacementLayer.Other);
for (ReplacementEffect newRE : reList) {
if (!replaceCandidateMap.containsKey(newRE)) {
replaceCandidateMap.put(newRE, new ArrayList<>());
}
List<Map<AbilityKey, Object>> runParamList = replaceCandidateMap.get(newRE);
runParamList.add(oldParams);
}
}
}
@SuppressWarnings("unchecked")
Map<ReplacementEffect, ReplacementResult> resultMap = (Map<ReplacementEffect, ReplacementResult>) runParams.get(AbilityKey.ReplacementResultMap);
resultMap.put(re, res);
// Update damage map and prevent map
switch (res) {
case NotReplaced:
break;
case Updated:
// check if this is still the affected card or player
if (target.equals(newTarget)) {
damageMap.put(source, target, newDamage - damage);
} else if (apiType == ApiType.ReplaceSplitDamage) {
damageMap.put(source, target, -newDamage);
}
if (!target.equals(newTarget)) {
if (apiType != ApiType.ReplaceSplitDamage) {
damageMap.remove(source, target);
}
damageMap.put(source, newTarget, newDamage);
}
if (apiType == ApiType.ReplaceDamage) {
preventMap.put(source, target, damage - newDamage);
// Record prevented amount
runParams.put(AbilityKey.PreventedAmount, damage - newDamage);
}
break;
default:
damageMap.remove(source, target);
if (apiType == ApiType.ReplaceDamage ||
(mapParams.containsKey("Prevent") && mapParams.get("Prevent").equals("True")) ||
mapParams.containsKey("PreventionEffect")) {
preventMap.put(source, target, damage);
// Record prevented amount
runParams.put(AbilityKey.PreventedAmount, damage);
}
if (apiType == ApiType.ReplaceSplitDamage) {
damageMap.put(source, newTarget, newDamage);
}
}
// Put run params into executed param list so this replacement effect won't handle them again
// (For example, if the damage is redirected back)
executedParamList.add(runParams);
if (apiType == ApiType.ReplaceSplitDamage) {
executedParamList.add(oldParams);
}
// Log the replacement effect
if (res != ReplacementResult.NotReplaced) {
String message = re.getDescription();
if ( !StringUtils.isEmpty(message)) {
if (re.getHostCard() != null) {
message = TextUtil.fastReplace(message, "CARDNAME", re.getHostCard().getName());
}
game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message);
}
}
}
private void executeReplaceDamageBufferedSA(Map<ReplacementEffect, List<Map<AbilityKey, Object>>> executedDamageMap) {
for (Map.Entry<ReplacementEffect, List<Map<AbilityKey, Object>>> entry : executedDamageMap.entrySet()) {
ReplacementEffect re = entry.getKey();
if (re.getOverridingAbility() == null) {
continue;
}
SpellAbility bufferedSA = re.getOverridingAbility();
ApiType apiType = bufferedSA.getApi();
if (apiType == ApiType.ReplaceDamage || apiType == ApiType.ReplaceSplitDamage || apiType == ApiType.ReplaceEffect) {
bufferedSA = bufferedSA.getSubAbility();
if (bufferedSA == null) {
continue;
}
}
List<Map<AbilityKey, Object>> executedParamList = entry.getValue();
if (executedParamList.isEmpty()) {
continue;
}
Map<String, String> mapParams = re.getMapParams();
boolean isPrevention = (mapParams.containsKey("Prevent") && mapParams.get("Prevent").equals("True")) || mapParams.containsKey("PreventionEffect");
boolean executePerSource = (mapParams.containsKey("ExecuteMode") && mapParams.get("ExecuteMode").equals("PerSource"));
boolean executePerTarget = (mapParams.containsKey("ExecuteMode") && mapParams.get("ExecuteMode").equals("PerTarget"));
while (!executedParamList.isEmpty()) {
Map<AbilityKey, Object> runParams = AbilityKey.newMap();
List<Card> damageSourceList = new ArrayList<>();
List<GameEntity> affectedList = new ArrayList<>();
int damageSum = 0;
Iterator<Map<AbilityKey, Object>> itr = executedParamList.iterator();
while (itr.hasNext()) {
Map<AbilityKey, Object> executedParams = itr.next();
@SuppressWarnings("unchecked")
Map<ReplacementEffect, ReplacementResult> resultMap = (Map<ReplacementEffect, ReplacementResult>) executedParams.get(AbilityKey.ReplacementResultMap);
ReplacementResult res = resultMap.get(re);
if (res == ReplacementResult.NotReplaced && (!isPrevention || Boolean.FALSE.equals(executedParams.get(AbilityKey.NoPreventDamage)))) {
itr.remove();
continue;
}
Card source = (Card) executedParams.get(AbilityKey.DamageSource);
if (executePerSource && !damageSourceList.isEmpty() && !damageSourceList.contains(source)) {
continue;
}
GameEntity target = (GameEntity) executedParams.get(AbilityKey.Affected);
if (executePerTarget && !affectedList.isEmpty() && !affectedList.contains(target)) {
continue;
}
itr.remove();
int damage = (int) executedParams.get(isPrevention ? AbilityKey.PreventedAmount : AbilityKey.DamageAmount);
if (!damageSourceList.contains(source)) {
damageSourceList.add(source);
}
if (!affectedList.contains(target)) {
affectedList.add(target);
}
damageSum += damage;
}
if (damageSum > 0) {
runParams.put(AbilityKey.DamageSource, (damageSourceList.size() > 1 ? damageSourceList : damageSourceList.get(0)));
runParams.put(AbilityKey.Affected, (affectedList.size() > 1 ? affectedList : affectedList.get(0)));
runParams.put(AbilityKey.DamageAmount, damageSum);
re.setReplacingObjects(runParams, re.getOverridingAbility());
bufferedSA.setActivatingPlayer(re.getHostCard().getController());
AbilityUtils.resolve(bufferedSA);
}
}
}
}
public void runReplaceDamage(final boolean isCombat, final CardDamageMap damageMap, final CardDamageMap preventMap,
final GameEntityCounterTable counterTable, final SpellAbility cause) {
PlayerCollection players = game.getPlayersInTurnOrder();
for (int i = 0; i < players.size(); i++) {
replaceDamageList.add(new HashMap<>());
}
// Map of all executed replacement effect for DamageDone event, including run params
Map<ReplacementEffect, List<Map<AbilityKey, Object>>> executedDamageMap = new HashMap<>();
// First, gather all possible replacement effects
getPossibleReplaceDamageList(players, isCombat, damageMap, cause);
// Next, handle replacement effects in APNAP order
// Handle "Prevented this way" and abilities like "Phantom Nomad", by buffer the replaced SA
// and only run them after all prevention and redirection effects are processed.
while (true) {
Player decider = null;
Map<ReplacementEffect, List<Map<AbilityKey, Object>>> replaceCandidateMap = null;
for (int i = 0; i < players.size(); i++) {
if (replaceDamageList.get(i).isEmpty()) continue;
decider = players.get(i);
replaceCandidateMap = replaceDamageList.get(i);
break;
}
if (replaceCandidateMap == null) {
break;
}
List<ReplacementEffect> possibleReplacers = new ArrayList<>(replaceCandidateMap.keySet());
ReplacementEffect chosenRE = decider.getController().chooseSingleReplacementEffect(Localizer.getInstance().getMessage("lblChooseFirstApplyReplacementEffect"), possibleReplacers);
List<Map<AbilityKey, Object>> runParamList = replaceCandidateMap.get(chosenRE);
if (!executedDamageMap.containsKey(chosenRE)) {
executedDamageMap.put(chosenRE, new ArrayList<>());
}
// Run all possible events for chosen replacement effect
chosenRE.setHasRun(true);
SpellAbility effectSA = chosenRE.getOverridingAbility();
SpellAbility bufferedSA = effectSA;
boolean needRestoreSubSA = false;
if (effectSA != null) {
ApiType apiType = effectSA.getApi();
// Temporary remove sub ability from ReplaceDamage, ReplaceSplitDamage and ReplaceEffect API so they could be run later
if (apiType == ApiType.ReplaceDamage || apiType == ApiType.ReplaceSplitDamage || apiType == ApiType.ReplaceEffect) {
bufferedSA = effectSA.getSubAbility();
if (bufferedSA != null) {
needRestoreSubSA = true;
effectSA.setSubAbility(null);
}
}
}
for (Map<AbilityKey, Object> runParams : runParamList) {
if (!runParams.containsKey(AbilityKey.ReplacementResultMap)) {
Map<ReplacementEffect, ReplacementResult> resultMap = new HashMap<>();
runParams.put(AbilityKey.ReplacementResultMap, resultMap);
}
runSingleReplaceDamageEffect(chosenRE, runParams, replaceCandidateMap, executedDamageMap, decider, damageMap, preventMap);
}
// Restore temporary removed SA
if (needRestoreSubSA) {
effectSA.setSubAbility((AbilitySub)bufferedSA);
}
chosenRE.setHasRun(false);
replaceCandidateMap.remove(chosenRE);
}
replaceDamageList.clear();
// Finally, run all buffered SA to finish the replacement processing
executeReplaceDamageBufferedSA(executedDamageMap);
}
/** /**
* *
* Creates an instance of the proper replacement effect object based on raw * Creates an instance of the proper replacement effect object based on raw

View File

@@ -14,6 +14,7 @@ import forge.gui.framework.DragTab;
import forge.gui.framework.EDocID; import forge.gui.framework.EDocID;
import forge.gui.framework.IVDoc; import forge.gui.framework.IVDoc;
import forge.screens.workshop.controllers.CCardScript; import forge.screens.workshop.controllers.CCardScript;
import forge.toolbox.FScrollPane;
import forge.toolbox.FTextPane; import forge.toolbox.FTextPane;
import forge.util.Localizer; import forge.util.Localizer;
import net.miginfocom.swing.MigLayout; import net.miginfocom.swing.MigLayout;
@@ -32,6 +33,7 @@ public enum VCardScript implements IVDoc<CCardScript> {
private final DragTab tab = new DragTab(Localizer.getInstance().getMessage("lblCardScript")); private final DragTab tab = new DragTab(Localizer.getInstance().getMessage("lblCardScript"));
private final FTextPane txtScript = new FTextPane(); private final FTextPane txtScript = new FTextPane();
private final FScrollPane scrollScript;
private final StyledDocument doc; private final StyledDocument doc;
private final Style error; private final Style error;
@@ -41,6 +43,7 @@ public enum VCardScript implements IVDoc<CCardScript> {
txtScript.setFocusable(true); txtScript.setFocusable(true);
doc = new DefaultStyledDocument(); doc = new DefaultStyledDocument();
txtScript.setDocument(doc); txtScript.setDocument(doc);
scrollScript = new FScrollPane(txtScript, true);
error = doc.addStyle("error", null); error = doc.addStyle("error", null);
error.addAttribute(StyleConstants.Background, Color.red); error.addAttribute(StyleConstants.Background, Color.red);
error.addAttribute(StyleConstants.Bold, Boolean.valueOf(true)); error.addAttribute(StyleConstants.Bold, Boolean.valueOf(true));
@@ -107,6 +110,6 @@ public enum VCardScript implements IVDoc<CCardScript> {
public void populate() { public void populate() {
JPanel body = parentCell.getBody(); JPanel body = parentCell.getBody();
body.setLayout(new MigLayout("insets 1, gap 0, wrap")); body.setLayout(new MigLayout("insets 1, gap 0, wrap"));
body.add(txtScript, "w 100%, h 100%"); body.add(scrollScript, "w 100%, h 100%");
} }
} }

View File

@@ -2166,4 +2166,149 @@ public class GameSimulatorTest extends SimulationTestCase {
assertEquals(true, simGoblin.isRed() && simGoblin.isBlack()); assertEquals(true, simGoblin.isRed() && simGoblin.isBlack());
assertEquals(true, simGoblin.getType().hasSubtype("Zombie")); assertEquals(true, simGoblin.getType().hasSubtype("Zombie"));
} }
public void testCantBePrevented() {
String polukranosCardName = "Polukranos, Unchained";
String hydraCardName = "Phyrexian Hydra";
String leylineCardName = "Leyline of Punishment";
Game game = initAndCreateGame();
Player p = game.getPlayers().get(0);
Card polukranos = addCard(polukranosCardName, p);
polukranos.addCounter(CounterEnumType.P1P1, 6, p, false, null);
addCard(hydraCardName, p);
addCard(leylineCardName, p);
for (int i = 0; i < 2; ++i) {
addCard("Mountain", p);
}
Card pyroCard = addCardToZone("Pyroclasm", p, ZoneType.Hand);
SpellAbility pyroSA = pyroCard.getFirstSpellAbility();
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
game.getAction().checkStateEffects(true);
GameSimulator sim = createSimulator(game, p);
sim.simulateSpellAbility(pyroSA);
Game simGame = sim.getSimulatedGameState();
Card simPolukranos = findCardWithName(simGame, polukranosCardName);
Card simHydra = findCardWithName(simGame, hydraCardName);
assertTrue(simPolukranos.hasCounters());
assertEquals(4, simPolukranos.getCounters(CounterEnumType.P1P1));
assertEquals(2, simPolukranos.getDamage());
assertFalse(simHydra.hasCounters());
assertEquals(2, simHydra.getDamage());
}
public void testAlphaBrawl() {
Game game = initAndCreateGame();
Player p1 = game.getPlayers().get(0);
Player p2 = game.getPlayers().get(1);
String nishobaName = "Phantom Nishoba";
String capridorName = "Stormwild Capridor";
String pridemateName = "Ajani's Pridemate";
String indestructibilityName = "Indestructibility";
String bearName = "Runeclaw Bear";
String alphaBrawlName = "Alpha Brawl";
// enough to cast Alpha Brawl
for (int i = 0; i < 8; ++i) {
addCard("Mountain", p2);
}
Card nishoba = addCard(nishobaName, p1);
nishoba.addCounter(CounterEnumType.P1P1, 7, p1, false, null);
addCard(capridorName, p1);
Card pridemate = addCard(pridemateName, p1);
Card indestructibility = addCard(indestructibilityName, p1);
indestructibility.attachToEntity(pridemate);
addCard(bearName, p1);
Card alphaBrawl = addCardToZone(alphaBrawlName, p2, ZoneType.Hand);
SpellAbility alphaBrawlSA = alphaBrawl.getFirstSpellAbility();
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p2);
game.getAction().checkStateEffects(true);
GameSimulator sim = createSimulator(game, p2);
alphaBrawlSA.setTargetCard(nishoba);
sim.simulateSpellAbility(alphaBrawlSA);
Game simGame = sim.getSimulatedGameState();
Card simNishoba = findCardWithName(simGame, nishobaName);
Card simCapridor = findCardWithName(simGame, capridorName);
Card simPridemate = findCardWithName(simGame, pridemateName);
Card simBear = findCardWithName(simGame, bearName);
// bear is destroyed
assertNull(simBear);
assertNotNull(simNishoba);
assertTrue(simNishoba.hasCounters());
// Damage prevented and only 1 +1/+1 counter is removed
assertEquals(0, simNishoba.getDamage());
assertTrue(simNishoba.hasCounters());
assertEquals(6, simNishoba.getCounters(CounterEnumType.P1P1));
assertEquals(6, simNishoba.getToughnessBonusFromCounters());
assertEquals(6, simNishoba.getPowerBonusFromCounters());
assertNotNull(simCapridor);
// Damage prevented and that many +1/+1 counters are put
assertEquals(0, simCapridor.getDamage());
assertTrue(simCapridor.hasCounters());
assertEquals(7, simCapridor.getCounters(CounterEnumType.P1P1));
assertEquals(7, simCapridor.getToughnessBonusFromCounters());
assertEquals(7, simCapridor.getPowerBonusFromCounters());
assertNotNull(simPridemate);
assertEquals(7, simPridemate.getDamage());
// Life gain only triggered once
assertTrue(simPridemate.hasCounters());
assertEquals(1, simPridemate.getCounters(CounterEnumType.P1P1));
assertEquals(1, simPridemate.getToughnessBonusFromCounters());
assertEquals(1, simPridemate.getPowerBonusFromCounters());
// 2 times 7 damage with life gain = 14 + 20 = 34 (damage to Stormwild Capridor is prevented)
assertEquals(34, simGame.getPlayers().get(0).getLife());
}
public void testGlarecaster() {
String glarecasterName = "Glarecaster";
Game game = initAndCreateGame();
Player p = game.getPlayers().get(0);
Player p2 = game.getPlayers().get(1);
Card glarecaster = addCard(glarecasterName, p);
// enough to activate Glarecaster and cast Inferno
for (int i = 0; i < 7; ++i) {
addCard("Plains", p);
addCard("Mountain", p);
}
Card infernoCard = addCardToZone("Inferno", p, ZoneType.Hand);
SpellAbility infernoSA = infernoCard.getFirstSpellAbility();
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
game.getAction().checkStateEffects(true);
SpellAbility saGlarecaster = findSAWithPrefix(glarecaster, "{5}{W}");
assertNotNull(saGlarecaster);
saGlarecaster.getTargets().add(p2);
GameSimulator sim = createSimulator(game, p);
int score = sim.simulateSpellAbility(saGlarecaster).value;
assertTrue(score > 0);
sim.simulateSpellAbility(infernoSA);
Game simGame = sim.getSimulatedGameState();
Card simGlarecaster = findCardWithName(simGame, glarecasterName);
assertNotNull(simGlarecaster);
assertEquals(0, simGlarecaster.getDamage());
// 6 * 3 = 18 damage are all dealt to p2
assertEquals(20, simGame.getPlayers().get(0).getLife());
assertEquals(2, simGame.getPlayers().get(1).getLife());
}
} }

View File

@@ -3,7 +3,6 @@ ManaCost:5 W
Types:Instant Types:Instant
A:SP$ Effect | Cost$ 5 W | ValidTgts$ Creature | ReplacementEffects$ ChannelHarmRep | RememberObjects$ Targeted | ExileOnMoved$ Battlefield | AILogic$ Fog | SpellDescription$ Prevent all damage that would be dealt to you and permanents you control this turn by sources you don't control. If damage is prevented this way, you may have CARDNAME deal that much damage to target creature. A:SP$ Effect | Cost$ 5 W | ValidTgts$ Creature | ReplacementEffects$ ChannelHarmRep | RememberObjects$ Targeted | ExileOnMoved$ Battlefield | AILogic$ Fog | SpellDescription$ Prevent all damage that would be dealt to you and permanents you control this turn by sources you don't control. If damage is prevented this way, you may have CARDNAME deal that much damage to target creature.
SVar:ChannelHarmRep:Event$ DamageDone | ActiveZones$ Command | ValidTarget$ You,Permanent.YouCtrl | ValidSource$ Card.YouDontCtrl,Emblem.YouDontCtrl | ReplaceWith$ DamageSourceInstead | PreventionEffect$ True | Description$ Prevent all damage that would be dealt to you and permanents you control this turn by sources you don't control. If damage is prevented this way, you may have EFFECTHOST deal that much damage to target creature. SVar:ChannelHarmRep:Event$ DamageDone | ActiveZones$ Command | ValidTarget$ You,Permanent.YouCtrl | ValidSource$ Card.YouDontCtrl,Emblem.YouDontCtrl | ReplaceWith$ DamageSourceInstead | PreventionEffect$ True | Description$ Prevent all damage that would be dealt to you and permanents you control this turn by sources you don't control. If damage is prevented this way, you may have EFFECTHOST deal that much damage to target creature.
SVar:DamageSourceInstead:DB$ DealDamage | NumDmg$ X | Defined$ Remembered | DamageSouce$ EffectSource | OptionalDecider$ You SVar:DamageSourceInstead:DB$ DealDamage | NumDmg$ X | Defined$ Remembered | DamageSource$ EffectSource | OptionalDecider$ You
SVar:X:ReplaceCount$DamageAmount SVar:X:ReplaceCount$DamageAmount
SVar:Picture:http://www.wizards.com/global/images/magic/general/channel_harm.jpg
Oracle:Prevent all damage that would be dealt to you and permanents you control this turn by sources you don't control. If damage is prevented this way, you may have Channel Harm deal that much damage to target creature. Oracle:Prevent all damage that would be dealt to you and permanents you control this turn by sources you don't control. If damage is prevented this way, you may have Channel Harm deal that much damage to target creature.

View File

@@ -2,9 +2,8 @@ Name:Comeuppance
ManaCost:3 W ManaCost:3 W
Types:Instant Types:Instant
A:SP$ Effect | Cost$ 3 W | ReplacementEffects$ RPrevent A:SP$ Effect | Cost$ 3 W | ReplacementEffects$ RPrevent
SVar:RPrevent:Event$ DamageDone | ValidSource$ Card.YouDontCtrl,Emblem.YouDontCtrl | ValidTarget$ You,Planeswalker.YouCtrl | ReplaceWith$ DamageCreature | PreventionEffect$ True | Description$ Prevent all damage that would be dealt to you and planeswalkers you control this turn by sources you don't control. If damage from a creature source is prevented this way, CARDNAME deals that much damage to that creature. If damage from a noncreature source is prevented this way, CARDNAME deals that much damage to the source's controller. SVar:RPrevent:Event$ DamageDone | ValidSource$ Card.YouDontCtrl,Emblem.YouDontCtrl | ValidTarget$ You,Planeswalker.YouCtrl | ReplaceWith$ DamageCreature | PreventionEffect$ True | ExecuteMode$ PerSource | Description$ Prevent all damage that would be dealt to you and planeswalkers you control this turn by sources you don't control. If damage from a creature source is prevented this way, CARDNAME deals that much damage to that creature. If damage from a noncreature source is prevented this way, CARDNAME deals that much damage to the source's controller.
SVar:DamageCreature:DB$ DealDamage | Defined$ ReplacedSource | DamageSource$ EffectSource | NumDmg$ X | ConditionDefined$ ReplacedSource | ConditionPresent$ Card.Creature | ConditionCompare$ GE1 | SubAbility$ DamageNonCreature SVar:DamageCreature:DB$ DealDamage | Defined$ ReplacedSource | DamageSource$ EffectSource | NumDmg$ X | ConditionDefined$ ReplacedSource | ConditionPresent$ Card.Creature | ConditionCompare$ GE1 | SubAbility$ DamageNonCreature
SVar:DamageNonCreature:DB$ DealDamage | Defined$ ReplacedSourceController | DamageSource$ EffectSource | NumDmg$ X | ConditionDefined$ ReplacedSource | ConditionPresent$ Card.nonCreature | ConditionCompare$ GE1 SVar:DamageNonCreature:DB$ DealDamage | Defined$ ReplacedSourceController | DamageSource$ EffectSource | NumDmg$ X | ConditionDefined$ ReplacedSource | ConditionPresent$ Card.nonCreature | ConditionCompare$ GE1
SVar:X:ReplaceCount$DamageAmount SVar:X:ReplaceCount$DamageAmount
SVar:Picture:http://www.wizards.com/global/images/magic/general/comeuppance.jpg
Oracle:Prevent all damage that would be dealt to you and planeswalkers you control this turn by sources you don't control. If damage from a creature source is prevented this way, Comeuppance deals that much damage to that creature. If damage from a noncreature source is prevented this way, Comeuppance deals that much damage to the source's controller. Oracle:Prevent all damage that would be dealt to you and planeswalkers you control this turn by sources you don't control. If damage from a creature source is prevented this way, Comeuppance deals that much damage to that creature. If damage from a noncreature source is prevented this way, Comeuppance deals that much damage to the source's controller.

View File

@@ -1,7 +1,7 @@
Name:Crumbling Sanctuary Name:Crumbling Sanctuary
ManaCost:5 ManaCost:5
Types:Artifact Types:Artifact
R:Event$ DamageDone | ActiveZones$ Battlefield | ValidTarget$ Player | ReplaceWith$ ExileTop | Description$ If damage would be dealt to a player, that player exiles that many cards from the top of their library instead. R:Event$ DamageDone | ActiveZones$ Battlefield | ValidTarget$ Player | ReplaceWith$ ExileTop | ExecuteMode$ PerTarget | Description$ If damage would be dealt to a player, that player exiles that many cards from the top of their library instead.
SVar:ExileTop:DB$ Dig | Defined$ ReplacedTarget | DigNum$ X | ChangeNum$ All | DestinationZone$ Exile SVar:ExileTop:DB$ Dig | Defined$ ReplacedTarget | DigNum$ X | ChangeNum$ All | DestinationZone$ Exile
SVar:X:ReplaceCount$DamageAmount SVar:X:ReplaceCount$DamageAmount
SVar:NonStackingEffect:True SVar:NonStackingEffect:True

View File

@@ -2,7 +2,7 @@ Name:Deep Water
ManaCost:U U ManaCost:U U
Types:Enchantment Types:Enchantment
A:AB$ Effect | Cost$ U | ReplacementEffects$ ReplaceU | SpellDescription$ Until end of turn, if you tap a land you control for mana, it produces {U} instead of any other type. A:AB$ Effect | Cost$ U | ReplacementEffects$ ReplaceU | SpellDescription$ Until end of turn, if you tap a land you control for mana, it produces {U} instead of any other type.
SVar:ReplaceU:Event$ ProduceMana | ActiveZones$ Command | ValidPlayer$ You | ValidCard$ Land.YouCtrl | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceU | Description$ If you tap a land you control for mana, it produces U instead of any other type. SVar:ReplaceU:Event$ ProduceMana | ActiveZones$ Command | ValidActivator$ You | ValidCard$ Land.YouCtrl | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceU | Description$ If you tap a land you control for mana, it produces U instead of any other type.
SVar:ProduceU:DB$ ReplaceMana | ReplaceType$ U SVar:ProduceU:DB$ ReplaceMana | ReplaceType$ U
AI:RemoveDeck:All AI:RemoveDeck:All
AI:RemoveDeck:Random AI:RemoveDeck:Random

View File

@@ -3,6 +3,6 @@ ManaCost:3 B
Types:Creature Human Pirate Types:Creature Human Pirate
PT:3/3 PT:3/3
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDestroy | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME enters the battlefield, destroy target creature an opponent controls that was dealt damage this turn. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDestroy | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME enters the battlefield, destroy target creature an opponent controls that was dealt damage this turn.
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Creature.OppCtrl+wasDealtDamageThisTurn | TgtPrompt$ Select target creature tan opponent controls that was dealt damage this turn. SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Creature.OppCtrl+wasDealtDamageThisTurn | TgtPrompt$ Select target creature an opponent controls that was dealt damage this turn.
SVar:Picture:http://www.wizards.com/global/images/magic/general/fathom_fleet_cutthroat.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/fathom_fleet_cutthroat.jpg
Oracle:When Fathom Fleet Cutthroat enters the battlefield, destroy target creature an opponent controls that was dealt damage this turn. Oracle:When Fathom Fleet Cutthroat enters the battlefield, destroy target creature an opponent controls that was dealt damage this turn.

View File

@@ -3,7 +3,7 @@ ManaCost:G
Types:Creature Human Spellshaper Types:Creature Human Spellshaper
PT:1/1 PT:1/1
A:AB$ Effect | Cost$ G T Discard<1/Card> | ReplacementEffects$ HarvestReplacement | AILogic$ Never | Stackable$ False | SpellDescription$ Until end of turn, if you tap a land for mana, it produces one mana of a color of your choice instead of any other type and amount. A:AB$ Effect | Cost$ G T Discard<1/Card> | ReplacementEffects$ HarvestReplacement | AILogic$ Never | Stackable$ False | SpellDescription$ Until end of turn, if you tap a land for mana, it produces one mana of a color of your choice instead of any other type and amount.
SVar:HarvestReplacement:Event$ ProduceMana | ActiveZones$ Command | ValidPlayer$ You | ValidCard$ Land | ValidAbility$ Activated.hasTapCost | ReplaceWith$ HarvestProduce | Description$ If you tap a land for mana, it produces one mana of a color of your choice instead of any other type and amount. SVar:HarvestReplacement:Event$ ProduceMana | ActiveZones$ Command | ValidActivator$ You | ValidCard$ Land | ValidAbility$ Activated.hasTapCost | ReplaceWith$ HarvestProduce | Description$ If you tap a land for mana, it produces one mana of a color of your choice instead of any other type and amount.
SVar:HarvestProduce:DB$ ReplaceMana | ReplaceMana$ Any SVar:HarvestProduce:DB$ ReplaceMana | ReplaceMana$ Any
AI:RemoveDeck:All AI:RemoveDeck:All
SVar:NonStackingEffect:True SVar:NonStackingEffect:True

View File

@@ -2,7 +2,7 @@ Name:Ironscale Hydra
ManaCost:3 G G ManaCost:3 G G
Types:Creature Hydra Types:Creature Hydra
PT:5/5 PT:5/5
R:Event$ DamageDone | ActiveZones$ Battlefield | ValidTarget$ Card.Self | ValidSource$ Creature | IsCombat$ True | ReplaceWith$ Counters | PreventionEffect$ True | AlwaysReplace$ True | Description$ If a creature would deal combat damage to CARDNAME, prevent that damage and put a +1/+1 counter on CARDNAME. R:Event$ DamageDone | ActiveZones$ Battlefield | ValidTarget$ Card.Self | ValidSource$ Creature | IsCombat$ True | ReplaceWith$ Counters | PreventionEffect$ True | AlwaysReplace$ True | ExecuteMode$ PerSource | Description$ If a creature would deal combat damage to CARDNAME, prevent that damage and put a +1/+1 counter on CARDNAME.
SVar:Counters:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 SVar:Counters:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
DeckHas:Ability$Counters DeckHas:Ability$Counters
Oracle:If a creature would deal combat damage to Ironscale Hydra, prevent that damage and put a +1/+1 counter on Ironscale Hydra. Oracle:If a creature would deal combat damage to Ironscale Hydra, prevent that damage and put a +1/+1 counter on Ironscale Hydra.

View File

@@ -1,6 +1,6 @@
Name:Mana Reflection Name:Mana Reflection
ManaCost:4 G G ManaCost:4 G G
Types:Enchantment Types:Enchantment
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidPlayer$ You | ValidCard$ Permanent | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceTwice | Description$ If you tap a permanent for mana, it produces twice as much of that mana instead. R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidActivator$ You | ValidCard$ Permanent | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceTwice | Description$ If you tap a permanent for mana, it produces twice as much of that mana instead.
SVar:ProduceTwice:DB$ ReplaceMana | ReplaceAmount$ 2 SVar:ProduceTwice:DB$ ReplaceMana | ReplaceAmount$ 2
Oracle:If you tap a permanent for mana, it produces twice as much of that mana instead. Oracle:If you tap a permanent for mana, it produces twice as much of that mana instead.

View File

@@ -2,7 +2,7 @@ Name:Nine Lives
ManaCost:1 W W ManaCost:1 W W
Types:Enchantment Types:Enchantment
K:Hexproof K:Hexproof
R:Event$ DamageDone | ActiveZones$ Battlefield | ValidSource$ Card,Emblem | ValidTarget$ You | PreventionEffect$ True | ReplaceWith$ AddCounters | AlwaysReplace$ True | Description$ If a source would deal damage to you, prevent that damage and put an incarnation counter on CARDNAME. R:Event$ DamageDone | ActiveZones$ Battlefield | ValidSource$ Card,Emblem | ValidTarget$ You | PreventionEffect$ True | ReplaceWith$ AddCounters | AlwaysReplace$ True | ExecuteMode$ PerSource | Description$ If a source would deal damage to you, prevent that damage and put an incarnation counter on CARDNAME.
SVar:AddCounters:DB$ PutCounter | Defined$ Self | CounterType$ INCARNATION | CounterNum$ 1 SVar:AddCounters:DB$ PutCounter | Defined$ Self | CounterType$ INCARNATION | CounterNum$ 1
T:Mode$ Always | TriggerZones$ Battlefield | IsPresent$ Card.Self+counters_GE9_INCARNATION | Execute$ TrigExile | TriggerDescription$ When there are nine or more incarnation counters on CARDNAME, exile it. T:Mode$ Always | TriggerZones$ Battlefield | IsPresent$ Card.Self+counters_GE9_INCARNATION | Execute$ TrigExile | TriggerDescription$ When there are nine or more incarnation counters on CARDNAME, exile it.
SVar:TrigExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | Defined$ Self SVar:TrigExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | Defined$ Self

View File

@@ -3,6 +3,6 @@ ManaCost:4 G G G
Types:Enchantment Creature Elemental Types:Enchantment Creature Elemental
PT:5/5 PT:5/5
K:Trample K:Trample
R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidCard$ Permanent.YouCtrl | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceThrice | Description$ If you tap a permanent for mana, it produces three times as much of that mana instead. R:Event$ ProduceMana | ActiveZones$ Battlefield | ValidActivator$ You | ValidCard$ Permanent | ValidAbility$ Activated.hasTapCost | ReplaceWith$ ProduceThrice | Description$ If you tap a permanent for mana, it produces three times as much of that mana instead.
SVar:ProduceThrice:DB$ ReplaceMana | ReplaceAmount$ 3 SVar:ProduceThrice:DB$ ReplaceMana | ReplaceAmount$ 3
Oracle:Trample\nIf you tap a permanent for mana, it produces three times as much of that mana instead. Oracle:Trample\nIf you tap a permanent for mana, it produces three times as much of that mana instead.

View File

@@ -6,12 +6,11 @@ K:Defender
K:Bushido:1 K:Bushido:1
A:AB$ ChooseSource | Cost$ T | Choices$ Card,Emblem | AILogic$ NeedsPrevention | SubAbility$ DBEffect | SpellDescription$ The next time a source of your choice would deal damage this turn, that damage is dealt to CARDNAME instead. A:AB$ ChooseSource | Cost$ T | Choices$ Card,Emblem | AILogic$ NeedsPrevention | SubAbility$ DBEffect | SpellDescription$ The next time a source of your choice would deal damage this turn, that damage is dealt to CARDNAME instead.
SVar:DBEffect:DB$ Effect | ReplacementEffects$ SelflessDamage | Triggers$ OutOfSight | Duration$ UntilHostLeavesPlayOrEOT | SubAbility$ DBCleanup | ConditionDefined$ ChosenCard | ConditionPresent$ Card,Emblem | ConditionCompare$ GE1 SVar:DBEffect:DB$ Effect | ReplacementEffects$ SelflessDamage | Triggers$ OutOfSight | Duration$ UntilHostLeavesPlayOrEOT | SubAbility$ DBCleanup | ConditionDefined$ ChosenCard | ConditionPresent$ Card,Emblem | ConditionCompare$ GE1
SVar:SelflessDamage:Event$ DamageDone | ValidTarget$ You | ValidSource$ Card.ChosenCard,Emblem.ChosenCard | ReplaceWith$ SelflessDmg | DamageTarget$ EffectSource | Description$ The next time a source of your choice would deal damage to you this turn, that damage is dealt to EFFECTSOURCE instead. SVar:SelflessDamage:Event$ DamageDone | ValidSource$ Card.ChosenCard,Emblem.ChosenCard | ReplaceWith$ SelflessDmg | DamageTarget$ EffectSource | Description$ The next time a source of your choice would deal damage to you this turn, that damage is dealt to EFFECTSOURCE instead.
SVar:SelflessDmg:DB$ ReplaceEffect | VarName$ Affected | VarValue$ EffectSource | VarType$ Card | SubAbility$ ExileEffect SVar:SelflessDmg:DB$ ReplaceEffect | VarName$ Affected | VarValue$ EffectSource | VarType$ Card | SubAbility$ ExileEffect
SVar:OutOfSight:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Defined$ ChosenCard | Execute$ ExileEffect | Static$ True SVar:OutOfSight:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Defined$ ChosenCard | Execute$ ExileEffect | Static$ True
SVar:ExileEffect:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile | Static$ True SVar:ExileEffect:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile | Static$ True
SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True
A:AB$ PreventDamage | Cost$ 1 W | Defined$ Self | Amount$ 1 | SpellDescription$ Prevent the next 1 damage that would be dealt to CARDNAME this turn. A:AB$ PreventDamage | Cost$ 1 W | Defined$ Self | Amount$ 1 | SpellDescription$ Prevent the next 1 damage that would be dealt to CARDNAME this turn.
AI:RemoveDeck:All AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/opal_eye_kondas_yojimbo.jpg
Oracle:Defender (This creature can't attack.)\nBushido 1 (Whenever this creature blocks or becomes blocked, it gets +1/+1 until end of turn.)\n{T}: The next time a source of your choice would deal damage this turn, that damage is dealt to Opal-Eye, Konda's Yojimbo instead.\n{1}{W}: Prevent the next 1 damage that would be dealt to Opal-Eye this turn. Oracle:Defender (This creature can't attack.)\nBushido 1 (Whenever this creature blocks or becomes blocked, it gets +1/+1 until end of turn.)\n{T}: The next time a source of your choice would deal damage this turn, that damage is dealt to Opal-Eye, Konda's Yojimbo instead.\n{1}{W}: Prevent the next 1 damage that would be dealt to Opal-Eye this turn.

View File

@@ -3,13 +3,6 @@ ManaCost:1 W
Types:Creature Spirit Nomad Types:Creature Spirit Nomad
PT:0/0 PT:0/0
K:etbCounter:P1P1:2 K:etbCounter:P1P1:2
T:Mode$ Phase | Static$ True | Phase$ First Strike Damage | Execute$ DBCleanup R:Event$ DamageDone | ActiveZones$ Battlefield | ValidTarget$ Card.Self | ReplaceWith$ DBRemoveCounters | PreventionEffect$ True | AlwaysReplace$ True | Description$ If damage would be dealt to CARDNAME, prevent that damage. Remove a +1/+1 counter from CARDNAME.
T:Mode$ Phase | Static$ True | Phase$ EndCombat | Execute$ DBCleanup
R:Event$ DamageDone | IsCombat$ True | ActiveZones$ Battlefield | ValidTarget$ Card.Self | ReplaceWith$ DBRemoveCountersInCombat | PreventionEffect$ True | AlwaysReplace$ True | Description$ If damage would be dealt to CARDNAME, prevent that damage. Remove a +1/+1 counter from CARDNAME.
R:Event$ DamageDone | IsCombat$ False | ActiveZones$ Battlefield | ValidTarget$ Card.Self | ReplaceWith$ DBRemoveCounters | PreventionEffect$ True | AlwaysReplace$ True | Secondary$ True | Description$ If damage would be dealt to CARDNAME, prevent that damage. Remove a +1/+1 counter from CARDNAME.
SVar:DBRemoveCountersInCombat:DB$ RemoveCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 | ConditionCheckSVar$ TimesFlagged | ConditionSVarCompare$ EQ0 | SubAbility$ DBFlagRemoveCounters
SVar:DBFlagRemoveCounters:DB$ StoreSVar | SVar$ TimesFlagged | Type$ CountSVar | Expression$ TimesFlagged/Plus.1
SVar:DBRemoveCounters:DB$ RemoveCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 SVar:DBRemoveCounters:DB$ RemoveCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
SVar:TimesFlagged:Number$0
SVar:DBCleanup:DB$ StoreSVar | SVar$ TimesFlagged | Type$ Number | Expression$ 0
Oracle:Phantom Nomad enters the battlefield with two +1/+1 counters on it.\nIf damage would be dealt to Phantom Nomad, prevent that damage. Remove a +1/+1 counter from Phantom Nomad. Oracle:Phantom Nomad enters the battlefield with two +1/+1 counters on it.\nIf damage would be dealt to Phantom Nomad, prevent that damage. Remove a +1/+1 counter from Phantom Nomad.

View File

@@ -3,9 +3,8 @@ ManaCost:R
Types:Creature Human Wizard Types:Creature Human Wizard
PT:1/2 PT:1/2
K:Prowess K:Prowess
R:Event$ DamageDone | ActiveZones$ Battlefield | ValidSource$ Card.YouCtrl,Emblem.YouCtrl | ValidTarget$ Creature.OppCtrl | ReplaceWith$ Counters | IsCombat$ False | Description$ If a source you control would deal noncombat damage to a creature an opponent controls, put that many -1/-1 counters on that creature instead. R:Event$ DamageDone | ActiveZones$ Battlefield | ValidSource$ Card.YouCtrl,Emblem.YouCtrl | ValidTarget$ Creature.OppCtrl | ReplaceWith$ Counters | IsCombat$ False | ExecuteMode$ PerTarget | Description$ If a source you control would deal noncombat damage to a creature an opponent controls, put that many -1/-1 counters on that creature instead.
SVar:Counters:DB$PutCounter | Defined$ ReplacedTarget | CounterType$ M1M1 | CounterNum$ X SVar:Counters:DB$PutCounter | Defined$ ReplacedTarget | CounterType$ M1M1 | CounterNum$ X
SVar:X:ReplaceCount$DamageAmount SVar:X:ReplaceCount$DamageAmount
DeckHas:Ability$Counters DeckHas:Ability$Counters
SVar:Picture:http://www.wizards.com/global/images/magic/general/soul_scar_mage.jpg
Oracle:Prowess\nIf a source you control would deal noncombat damage to a creature an opponent controls, put that many -1/-1 counters on that creature instead. Oracle:Prowess\nIf a source you control would deal noncombat damage to a creature an opponent controls, put that many -1/-1 counters on that creature instead.

View File

@@ -3,8 +3,7 @@ ManaCost:2 WU WU
Types:Creature Bird Spirit Types:Creature Bird Spirit
PT:4/3 PT:4/3
K:Flying K:Flying
R:Event$ DamageDone | ActiveZones$ Battlefield | ValidTarget$ Card.Self | ReplaceWith$ DBDraw | PreventionEffect$ True | Description$ If a source would deal damage to CARDNAME, prevent that damage. The source's controller draws cards equal to the damage prevented this way. R:Event$ DamageDone | ActiveZones$ Battlefield | ValidTarget$ Card.Self | ReplaceWith$ DBDraw | PreventionEffect$ True | ExecuteMode$ PerSource | Description$ If a source would deal damage to CARDNAME, prevent that damage. The source's controller draws cards equal to the damage prevented this way.
SVar:DBDraw:DB$ Draw | NumCards$ X | Defined$ ReplacedSourceController SVar:DBDraw:DB$ Draw | NumCards$ X | Defined$ ReplacedSourceController
SVar:X:ReplaceCount$DamageAmount SVar:X:ReplaceCount$DamageAmount
SVar:Picture:http://www.wizards.com/global/images/magic/general/swans_of_bryn_argoll.jpg
Oracle:Flying\nIf a source would deal damage to Swans of Bryn Argoll, prevent that damage. The source's controller draws cards equal to the damage prevented this way. Oracle:Flying\nIf a source would deal damage to Swans of Bryn Argoll, prevent that damage. The source's controller draws cards equal to the damage prevented this way.

View File

@@ -3,7 +3,7 @@ ManaCost:3 U U B B
Types:Legendary Creature Vampire Types:Legendary Creature Vampire
PT:5/5 PT:5/5
K:Flying K:Flying
R:Event$ DamageDone | ActiveZones$ Battlefield | IsCombat$ True | ValidSource$ Card.Self | ValidTarget$ Opponent | ReplaceWith$ CountersAndMill | Description$ If CARDNAME would deal combat damage to a player, instead put that many +1/+1 counters on Szadek and that player mills that many cards. R:Event$ DamageDone | ActiveZones$ Battlefield | IsCombat$ True | ValidSource$ Card.Self | ValidTarget$ Player | ReplaceWith$ CountersAndMill | ExecuteMode$ PerTarget | Description$ If CARDNAME would deal combat damage to a player, instead put that many +1/+1 counters on Szadek and that player mills that many cards.
SVar:X:ReplaceCount$DamageAmount SVar:X:ReplaceCount$DamageAmount
SVar:CountersAndMill:DB$ PutCounter | Defined$ Self | CounterNum$ X | CounterType$ P1P1 | SubAbility$ Mill SVar:CountersAndMill:DB$ PutCounter | Defined$ Self | CounterNum$ X | CounterType$ P1P1 | SubAbility$ Mill
SVar:Mill:DB$ Mill | Defined$ ReplacedTarget | NumCards$ X SVar:Mill:DB$ Mill | Defined$ ReplacedTarget | NumCards$ X

View File

@@ -2,7 +2,7 @@ Name:Undead Alchemist
ManaCost:3 U ManaCost:3 U
Types:Creature Zombie Types:Creature Zombie
PT:4/2 PT:4/2
R:Event$ DamageDone | ActiveZones$ Battlefield | ValidSource$ Creature.Zombie+YouCtrl | ValidTarget$ Opponent | ReplaceWith$ Mill | IsCombat$ True | Description$ If a Zombie you control would deal combat damage to a player, instead that player mills that many cards. R:Event$ DamageDone | ActiveZones$ Battlefield | ValidSource$ Creature.Zombie+YouCtrl | ValidTarget$ Player | ReplaceWith$ Mill | IsCombat$ True | ExecuteMode$ PerTarget | Description$ If a Zombie you control would deal combat damage to a player, instead that player mills that many cards.
SVar:Mill:DB$ Mill | Defined$ ReplacedTarget | NumCards$ X SVar:Mill:DB$ Mill | Defined$ ReplacedTarget | NumCards$ X
SVar:X:ReplaceCount$DamageAmount SVar:X:ReplaceCount$DamageAmount
T:Mode$ ChangesZone | ValidCard$ Creature.nonToken+OppOwn | Origin$ Library | Destination$ Graveyard | Execute$ ExileAndToken | TriggerZones$ Battlefield | TriggerDescription$ Whenever a creature card is put into an opponent's graveyard from their library, exile that card and create a 2/2 black Zombie creature token. T:Mode$ ChangesZone | ValidCard$ Creature.nonToken+OppOwn | Origin$ Library | Destination$ Graveyard | Execute$ ExileAndToken | TriggerZones$ Battlefield | TriggerDescription$ Whenever a creature card is put into an opponent's graveyard from their library, exile that card and create a 2/2 black Zombie creature token.

View File

@@ -0,0 +1,9 @@
Name:Abiding Grace
ManaCost:2 W
Types:Enchantment
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigCharm | TriggerDescription$ At the beginning of your end step, ABILITY
SVar:TrigCharm:DB$ Charm | Choices$ DBGainLife,DBChangeZone | CharmNum$ 1
SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 1 | SpellDescription$ You gain 1 life.
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | TgtPrompt$ Choose target creature card with mana value 1 in your graveyard | ValidTgts$ Creature.cmcEQ1+YouCtrl | SpellDescription$ Return target creature card with mana value 1 from your graveyard to the battlefield.
DeckHas:Ability$LifeGain
Oracle:At the beginning of your end step, choose one —\n• You gain 1 life.\n• Return target creature card with mana value 1 from your graveyard to the battlefield.

View File

@@ -0,0 +1,10 @@
Name:Aeve, Progenitor Ooze
ManaCost:2 G G G
Types:Legendary Creature Ooze
PT:2/2
K:Storm
S:Mode$ Continuous | Affected$ Card.token+Self | RemoveType$ Legendary | Description$ CARDNAME is not legendary if it's a token.
K:etbCounter:P1P1:X:no condition:CARDNAME enters the battlefield with a +1/+1 counter on it for each other Ooze you control.
SVar:X:Count$LastStateBattlefield Ooze.YouCtrl+Other
DeckHas:Ability$Counters
Oracle:Storm (When you cast this spell, copy it for each spell cast before it this turn. The copies become tokens.)\nAeve, Progenitor Ooze is not legendary if it's a token.\nAeve enters the battlefield with a +1/+1 counter on it for each other Ooze you control.

View File

@@ -0,0 +1,9 @@
Name:Altar of the Goyf
ManaCost:5
Types:Tribal Artifact Lhurgoyf
T:Mode$ Attacks | ValidCard$ Creature.YouCtrl | Alone$ True | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Whenever a creature you control attacks alone, it gets +X/+X until end of turn, where X is the number of card types among cards in all graveyards.
SVar:TrigPump:DB$ Pump | Defined$ TriggeredAttacker | NumAtt$ +X | NumDef$ +X
S:Mode$ Continuous | Affected$ Creature.Lhurgoyf+YouCtrl | AddKeyword$ Trample | Description$ Lhurgoyf creatures you control have trample.
SVar:X:Count$CardTypes.Graveyard
SVar:PlayMain1:TRUE
Oracle:Whenever a creature you control attacks alone, it gets +X/+X until end of turn, where X is the number of card types among cards in all graveyards.\nLhurgoyf creatures you control have trample.

View File

@@ -0,0 +1,11 @@
Name:Arcbound Shikari
ManaCost:1 R W
Types:Artifact Creature Cat Soldier
PT:0/0
K:First Strike
T:Mode$ ChangesZone | ValidCard$ Card.Self | Destination$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ When CARDNAME enters the battlefield, put a +1/+1 counter on each other artifact creature you control.
SVar:TrigPutCounter:DB$ PutCounterAll | ValidCards$ Creature.Artifact+Other+YouCtrl | CounterType$ P1P1 | CounterNum$ 1
K:Modular:2
DeckHas:Ability$Counters
SVar:PlayMain1:TRUE
Oracle:First strike\nWhen Arcbound Shikari enters the battlefield, put a +1/+1 counter on each other artifact creature you control.\nModular 2 (This creature enters the battlefield with two +1/+1 counters on it. When it does, you may put its counters on target artifact creature.)

View File

@@ -0,0 +1,14 @@
Name:Archon of Cruelty
ManaCost:6 B B
Types:Creature Archon
PT:6/6
K:Flying
T:Mode$ ChangesZone | ValidCard$ Card.Self | Destination$ Battlefield | Execute$ TrigSac | TriggerDescription$ Whenever CARDNAME enters the battlefield or attacks, target opponent sacrifices a creature or planeswalker, discards a card, and loses 3 life. You draw a card and gain 3 life.
T:Mode$ Attacks | ValidCard$ Card.Self | Secondary$ True | Execute$ TrigSac | TriggerDescription$ Whenever CARDNAME enters the battlefield or attacks, target opponent sacrifices a creature or planeswalker, discards a card, and loses 3 life. You draw a card and gain 3 life.
SVar:TrigSac:DB$ Sacrifice | ValidTgts$ Opponent | TgtPrompt$ Select target opponent | SacValid$ Creature,Planeswalker | SacMessage$ creature or planeswalker | SubAbility$ DBDiscard
SVar:DBDiscard:DB$ Discard | Defined$ Targeted | NumCards$ 1 | Mode$ TgtChoose | SubAbility$ DBLoseLife
SVar:DBLoseLife:DB$ LoseLife | Defined$ Targeted | LifeAmount$ 3 | SubAbility$ DBDraw
SVar:DBDraw:DB$ Draw | SubAbility$ DBGainLife
SVar:DBGainLife:DB$ GainLife | LifeAmount$ 3
DeckHas:Ability$LifeGain
Oracle:Flying\nWhenever Archon of Cruelty enters the battlefield or attacks, target opponent sacrifices a creature or planeswalker, discards a card, and loses 3 life. You draw a card and gain 3 life.

View File

@@ -0,0 +1,8 @@
Name:Batterbone
ManaCost:2
Types:Artifact Equipment
K:Living Weapon
K:Equip:5
S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 1 | AddToughness$ 1 | AddKeyword$ Vigilance & Lifelink | Description$ Equipped creature gets +1/+1 and has vigilance and lifelink.
DeckHas:Ability$LifeGain & Ability$Token
Oracle:Living weapon (When this Equipment enters the battlefield, create a 0/0 black Phyrexian Germ creature token, then attach this to it.)\nEquipped creature gets +1/+1 and has vigilance and lifelink.\nEquip {5}

View File

@@ -0,0 +1,10 @@
Name:Bottle Golems
ManaCost:4
Types:Artifact Creature Golem
PT:3/3
K:Trample
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigSac | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, you gain life equal to its power.
SVar:TrigSac:DB$GainLife | Defined$ TriggeredCardController | LifeAmount$ XPower
SVar:XPower:TriggeredCard$CardPower
DeckHas:Ability$LifeGain
Oracle:Trample\nWhen Bottle Golems dies, you gain life equal to its power.

View File

@@ -0,0 +1,7 @@
Name:Chatterstorm
ManaCost:1 G
Types:Sorcery
K:Storm
A:SP$ Token | Cost$ 1 G | TokenAmount$ 1 | TokenScript$ g_1_1_squirrel | TokenOwner$ You | SpellDescription$ Create a 1/1 green Squirrel creature token.
DeckHas:Ability$Token
Oracle:Create a 1/1 green Squirrel creature token.\nStorm (When you cast this spell, copy it for each spell cast before it this turn.)

View File

@@ -0,0 +1,11 @@
Name:Drey Keeper
ManaCost:3 B G
Types:Creature Elf Druid
PT:2/2
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield, create two 1/1 green Squirrel creature tokens.
SVar:TrigToken:DB$ Token | TokenAmount$ 2 | TokenScript$ g_1_1_squirrel | TokenOwner$ You
A:AB$ PumpAll | Cost$ 3 B | ValidCards$ Squirrel.YouCtrl | NumAtt$ +1 | KW$ Menace | SpellDescription$ Squirrels you control get +1/+0 and gain menace until end of turn.
SVar:PlayMain1:TRUE
DeckNeeds:Type$Squirrel
DeckHas:Ability$Token
Oracle:When Drey Keeper enters the battlefield, create two 1/1 green Squirrel creature tokens.\n{3}{B}: Squirrels you control get +1/+0 and gain menace until end of turn.

View File

@@ -0,0 +1,10 @@
Name:Endurance
ManaCost:1 G G
Types:Creature Elemental Incarnation
PT:3/4
K:Flash
K:Reach
K:Evoke:ExileFromHand<1/Card.Green+Other>
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigBottom | TriggerDescription$ When CARDNAME enters the battlefield, up to one target player puts all the cards from their graveyard on the bottom of their library in a random order.
SVar:TrigBottom:DB$ ChangeZoneAll | ValidTgts$ Player | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Select up to one target player | ChangeType$ Card | Origin$ Graveyard | Destination$ Library | Reveal$ False | RandomOrder$ True
Oracle:Flash\nReach\nWhen Endurance enters the battlefield, up to one target player puts all the cards from their graveyard on the bottom of their library in a random order.\nEvoke — Exile a green card from your hand.

View File

@@ -0,0 +1,12 @@
Name:Fae Offering
ManaCost:2 G
Types:Enchantment
T:Mode$ Phase | Phase$ End of Turn | TriggerZones$ Battlefield | CheckSVar$ Z | SVarCompare$ GE2 | Execute$ TrigTokenClue | TriggerDescription$ At the beginning of each end step, if you cast a creature and non-creature spell this turn, create a Clue token, a Food token, and a Treasure token.
SVar:TrigTokenClue:DB$ Token | TokenAmount$ 1 | TokenScript$ c_a_clue_draw | TokenOwner$ You | SubAbility$ TrigTokenFood
SVar:TrigTokenFood:DB$ Token | TokenAmount$ 1 | TokenScript$ c_a_food_sac | TokenOwner$ You | SubAbility$ TrigTokenTreasure
SVar:TrigTokenTreasure:DB$ Token | TokenAmount$ 1 | TokenScript$ c_a_treasure_sac | TokenOwner$ You
SVar:X:Count$ThisTurnCast_Creature.YouCtrl/LimitMax.1
SVar:Y:Count$ThisTurnCast_Card.nonCreature+YouCtrl/LimitMax.1
SVar:Z:SVar$X/Plus.Y
DeckHas:Ability$Token
Oracle:At the beginning of each end step, if you cast a creature and non-creature spell this turn, create a Clue token, a Food token, and a Treasure token.

View File

@@ -0,0 +1,16 @@
Name:Fast
ManaCost:2 R
Types:Instant
A:SP$ Discard | NumCards$ 1 | Mode$ TgtChoose | SubAbility$ DBDraw | SpellDescription$ Discard a card, then draw two cards.
SVar:DBDraw:DB$ Draw | NumCards$ 2
DeckHas:Ability$Discard
AlternateMode:Split
Oracle:Discard a card, then draw two cards.
ALTERNATE
Name:Furious
ManaCost:3 R R
Types:Sorcery
A:SP$ DamageAll | ValidCards$ Creature.withoutFlying | NumDmg$ 3 | ValidDescription$ each creature without flying | SpellDescription$ CARDNAME deals 3 damage to each creature without flying.
Oracle:Furious deals 3 damage to each creature without flying.

View File

@@ -0,0 +1,11 @@
Name:Gaea's Will
ManaCost:no cost
Types:Sorcery
Colors:green
K:Suspend:4:G
A:SP$ Effect | Cost$ 0 | Name$ Yawgmoth's Will Effect | ReplacementEffects$ GraveToExile | StaticAbilities$ STPlay | AILogic$ YawgmothsWill | AINoRecursiveCheck$ True | SpellDescription$ Until end of turn, you may play lands and cast spells from your graveyard. If a card would be put into your graveyard from anywhere this turn, exile that card instead.
SVar:STPlay:Mode$ Continuous | EffectZone$ Command | Affected$ Card.YouCtrl | AffectedZone$ Graveyard | MayPlay$ True | Description$ You may play cards from your graveyard.
SVar:GraveToExile:Event$ Moved | ActiveZones$ Command | Destination$ Graveyard | ValidCard$ Card.nonToken+YouOwn | ReplaceWith$ Exile | Description$ If a card would be put into your graveyard from anywhere, exile it instead.
SVar:Exile:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Exile | Defined$ ReplacedCard
SVar:PlayMain1:ALWAYS
Oracle:Suspend 4 — {G}\nUntil end of turn, you may play lands and cast spells from your graveyard.\nIf a card would be put into your graveyard from anywhere this turn, exile that card instead.

View File

@@ -0,0 +1,11 @@
Name:General Ferrous Rokiric
ManaCost:1 R W
Types:Legendary Creature Human Soldier
PT:3/1
K:Hexproof:Card.MonoColor:monocolored
T:Mode$ SpellCast | ValidCard$ Card.MultiColor | ValidActivatingPlayer$ You | Execute$ TrigToken | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast a multicolored spell, create a 4/4 red and white Golem creature token.
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenOwner$ You | TokenScript$ rw_4_4_golem
AI:RemoveDeck:Random
SVar:BuffedBy:Card.MultiColor
DeckHas:Ability$Token
Oracle:Hexproof from monocolored (This creature can't be the target of monocolored spells or abilities your opponents control.)\nWhenever you cast a multicolored spell, create a 4/4 red and white Golem creature token.

View File

@@ -0,0 +1,14 @@
Name:Geyadrone Dihada
ManaCost:1 U B R
Types:Legendary Planeswalker Dihada
Loyalty:4
S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ Protection:Permanent.counters_GE1_CORRUPTION:Protection from permanents with corruption counters on them | Description$ Protection from permanents with corruption counters on them
A:AB$ Pump | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Choose up to one other target creature or planeswalker | ValidTgts$ Creature.Other,Planeswalker.Other | SubAbility$ DBLoseLife | SpellDescription$ Each opponent loses 2 life and you gain 2 life. Put a corruption counter on up to one other target creature or planeswalker.
SVar:DBLoseLife:DB$ LoseLife | Defined$ Player.Opponent | LifeAmount$ 2 | SubAbility$ DBGainLife
SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 2 | SubAbility$ DBPutCounter
SVar:DBPutCounter:DB$ PutCounter | Defined$ Targeted | CounterType$ CORRUPTION | CounterNum$ 1
A:AB$ GainControl | Cost$ SubCounter<3/LOYALTY> | Planeswalker$ True | ValidTgts$ Creature,Planeswalker | TgtPrompt$ Select target creature or planeswalker | LoseControl$ EOT | Untap$ True | AddKWs$ Haste | SubAbility$ DBPutCounter | SpellDescription$ Gain control of target creature or planeswalker until end of turn. Untap it and put a corruption counter on it. It gains haste until end of turn.
SVar:DBPutCounter:DB$PutCounter | Defined$ Targeted | CounterType$ CORRUPTION | CounterNum$ 1
A:AB$ GainControl | Cost$ SubCounter<7/LOYALTY> | Planeswalker$ True | Ultimate$ True | AllValid$ Permanent.counters_GE1_CORRUPTION | SpellDescription$ Gain control of each permanent with a corruption counter on it.
DeckHas:Ability$LifeGain
Oracle:Protection from permanents with corruption counters on them\n[+1]: Each opponent loses 2 life and you gain 2 life. Put a corruption counter on up to one other target creature or planeswalker.\n[3]: Gain control of target creature or planeswalker until end of turn. Untap it and put a corruption counter on it. It gains haste until end of turn.\n[7]: Gain control of each permanent with a corruption counter on it.

View File

@@ -0,0 +1,10 @@
Name:Glinting Creeper
ManaCost:4 G
Types:Creature Plant
PT:0/0
K:etbCounter:P1P1:Y:no Condition:Converge — CARDNAME enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.
K:CantBeBlockedBy Creature.powerLE2
SVar:X:Count$Converge
SVar:Y:SVar$X/Twice
DeckHints:Ability$Counters
Oracle:Converge — Glinting Creeper enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.\nGlinting Creeper can't be blocked by creautures with power 2 or less.

View File

@@ -0,0 +1,9 @@
Name:Herd Baloth
ManaCost:3 G G
Types:Creature Beast
PT:4/4
T:Mode$ CounterAddedOnce | ValidCard$ Card.Self | TriggerZones$ Battlefield | CounterType$ P1P1 | Execute$ TrigToken | OptionalDecider$ You | TriggerDescription$ Whenever one or more +1/+1 counters are put on CARDNAME, you may create a 4/4 green Beast creature token.
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ g_4_4_beast | TokenOwner$ You
DeckHints:Ability$Counters
DeckHas:Ability$Token
Oracle:Whenever one or more +1/+1 counters are put on Herd Baloth, you may create a 4/4 green Beast creature token.

View File

@@ -0,0 +1,9 @@
Name:Ignoble Hierarch
ManaCost:G
Types:Creature Goblin Shaman
PT:0/1
A:AB$ Mana | Cost$ T | Produced$ B | SpellDescription$ Add {B}.
A:AB$ Mana | Cost$ T | Produced$ R | SpellDescription$ Add {R}.
A:AB$ Mana | Cost$ T | Produced$ G | SpellDescription$ Add {G}.
K:Exalted
Oracle:Exalted (Whenever a creature you control attacks alone, that creature gets +1/+1 until end of turn.)\n{T}: Add {B}, {R}, or {G}.

View File

@@ -0,0 +1,6 @@
Name:Jade Avenger
ManaCost:1 G
Types:Creature Frog Samurai
PT:2/2
K:Bushido:2
Oracle:Bushido 2 (Whenever this creature blocks or becomes blocked, it gets +2/+2 until end of turn.)

View File

@@ -2,9 +2,9 @@ Name:Junk Winder
ManaCost:5 U U ManaCost:5 U U
Types:Creature Serpent Types:Creature Serpent
PT:5/6 PT:5/6
K:Affinity:Permanent.token K:Affinity:Permanent.token:token
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Permanent.token+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigTap | TriggerDescription$ Whenever a token enters the battlefield under your control, tap target nonland permanent an opponent controls. It doesn't untap during its controller's next untap step. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Permanent.token+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigTap | TriggerDescription$ Whenever a token enters the battlefield under your control, tap target nonland permanent an opponent controls. It doesn't untap during its controller's next untap step.
SVar:TrigTap:DB$ Tap | ValidTgts$ Permanent.nonLand+OppCtrl | TgtPrompt$ Choose target nonland permanent an opponent controls | SubAbility$ DBPump SVar:TrigTap:DB$ Tap | ValidTgts$ Permanent.nonLand+OppCtrl | TgtPrompt$ Choose target nonland permanent an opponent controls | SubAbility$ DBPump
SVar:DBPump:DB$ Pump | Defined$ Targeted | KW$ HIDDEN This card doesn't untap during your next untap step. | Permanent$ True SVar:DBPump:DB$ Pump | Defined$ Targeted | KW$ HIDDEN This card doesn't untap during your next untap step. | Duration$ Permanent
DeckNeeds:Ability$Token DeckNeeds:Ability$Token
Oracle:Affinity for tokens (This spell costs {1} less to cast for each token you control.)\nWhenever a token enters the battlefield under your control, tap target nonland permanent an opponent controls. It doesn't untap during its controller's next untap step. Oracle:Affinity for tokens (This spell costs {1} less to cast for each token you control.)\nWhenever a token enters the battlefield under your control, tap target nonland permanent an opponent controls. It doesn't untap during its controller's next untap step.

View File

@@ -0,0 +1,15 @@
Name:Lonis, Cryptozoologist
ManaCost:G U
Types:Legendary Creature Snake Elf Scout
PT:1/2
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.YouCtrl+nonToken+Other | TriggerZones$ Battlefield | Execute$ TrigInvestigate | TriggerDescription$ Whenever another nontoken creature enters the battlefield under your control, investigate. (Create a colorless Clue artifact token with "{2}, Sacrifice this artifact: Draw a card.")
SVar:TrigInvestigate:DB$ Investigate
A:AB$ Dig | Cost$ T Sac<X/Clue> | ValidTgts$ Player.Opponent | TgtPrompt$ Select target opponent | Reveal$ True | NoMove$ True | DigNum$ X | RememberRevealed$ True | DestinationZone$ Library | SubAbility$ PickOne | SpellDescription$ Target opponent reveals the top X cards of their library. You may put a nonland permanent card with mana value X or less from among them onto the battlefield under your control. That player puts the rest on the bottom of their library in a random order.
SVar:PickOne:DB$ ChooseCard | Defined$ You | Amount$ 1 | Mandatory$ True | ChoiceTitle$ Choose a nonland permanent to put on the battlefield under your control | Choices$ Permanent.nonLand+cmcLEX+IsRemembered | ChoiceZone$ Library | SubAbility$ MoveChosen
SVar:MoveChosen:DB$ ChangeZone | Origin$ Library | Destination$ Battlefield | GainControl$ True | Defined$ ChosenCard | SubAbility$ DBBottom
SVar:DBBottom:DB$ ChangeZoneAll | ChangeType$ Card.IsRemembered | Origin$ Library | Destination$ Library | LibraryPosition$ -1 | RandomOrder$ True | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Count$xPaid
DeckHints:Ability$Investigate
DeckHas:Ability$Investigate & Ability$Token
Oracle:Whenever another nontoken creature enters the battlefield under your control, investigate. (Create a colorless Clue artifact token with "{2}, Sacrifice this artifact: Draw a card.")\n{T}, Sacrifice X Clues: Target opponent reveals the top X cards of their library. You may put a nonland permanent card with mana value X or less from among them onto the battlefield under your control. That player puts the rest on the bottom of their library in a random order.

View File

@@ -0,0 +1,6 @@
Name:Lose Focus
ManaCost:1 U
Types:Instant
K:Replicate:U
A:SP$ Counter | Cost$ 1 U | TargetType$ Spell | TgtPrompt$ Select target spell | ValidTgts$ Card | UnlessCost$ 2 | SpellDescription$ Counter target spell unless its controller pays {2}.
Oracle:Replicate {U} (When you cast this spell, copy it for each time you paid its replicate cost. You may choose new targets for the copies.)\nCounter target spell unless its controller pays {2}.

View File

@@ -0,0 +1,7 @@
Name:Moderation
ManaCost:1 W U
Types:Enchantment
S:Mode$ CantBeCast | ValidCard$ Card | Caster$ You | NumLimitEachTurn$ 1 | Description$ You can't cast more than one spell each turn.
T:Mode$ SpellCast | ValidActivatingPlayer$ You | Execute$ TrigDraw | TriggerDescription$ Whenever you cast a spell, draw a card.
SVar:TrigDraw:DB$ Draw | NumCards$ 1
Oracle:You can't cast more than one spell each turn.\nWhenever you cast a spell, draw a card.

View File

@@ -0,0 +1,8 @@
Name:Monoskelion
ManaCost:2
Types:Artifact Creature Construct
PT:1/1
K:etbCounter:P1P1:1
A:AB$ DealDamage | AILogic$ Triskelion | Cost$ SubCounter<1/P1P1> | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ 1 | SpellDescription$ CARDNAME deals 1 damage to any target.
DeckHas:Ability$Counters
Oracle:Monoskelion enters the battlefield with a +1/+1 counter on it.\nRemove a +1/+1 counter from Monoskelion: It deals 1 damage to any target.

View File

@@ -0,0 +1,12 @@
Name:Nettlecyst
ManaCost:3
Types:Artifact Equipment
K:Living Weapon
K:Equip:2
S:Mode$ Continuous | Affected$ Card.EquippedBy | AddPower$ X | AddToughness$ X | Description$ Equipped creature gets +1/+1 for each artifact and/or enchantment you control.
SVar:X:Count$Valid Artifact.YouCtrl,Enchantment.YouCtrl
SVar:NeedsToPlayVar:X GE1
SVar:BuffedBy:Artifact,Enchantment
DeckHas:Ability$Token
DeckHints:Type$Artifact|Enchantment
Oracle:Living weapon (When this Equipment enters the battlefield, create a 0/0 black Germ creature token, then attach this to it.)\nEquipped creature gets +1/+1 for each artifact and/or enchantment you control.\nEquip {2}

View File

@@ -0,0 +1,9 @@
Name:Orchard Strider
ManaCost:4 G G
Types:Creature Treefolk
PT:6/4
T:Mode$ ChangesZone | ValidCard$ Card.Self | Destination$ Battlefield | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield, create two Food tokens. (They're artifacts with "{2}, {T}, Sacrifice this artifact: You gain 3 life.")
SVar:TrigToken:DB$ Token | TokenScript$ c_a_food_sac | TokenAmount$ 2
K:TypeCycling:Basic:1 G
DeckHas:Ability$Token & Ability$LifeGain
Oracle:When Orchard Strider enters the battlefield, create two Food tokens. (They're artifacts with "{2}, {T}, Sacrifice this artifact: You gain 3 life.")\nBasic landcycling {1}{G} ({1}{G}, Discard this card: Search your library for a basic land card, reveal it, put it into your hand, then shuffle.)

View File

@@ -0,0 +1,10 @@
Name:Piru, the Volatile
ManaCost:2 R R W W B B
Types:Legendary Creature Elder Dragon
PT:7/7
K:Flying
K:Lifelink
K:UpkeepCost:R W B
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigDamage | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, it deals 7 damage to each nonlegendary creature.
SVar:TrigDamage:DB$ DamageAll | ValidCards$ Creature.nonLegendary | NumDmg$ 7 | ValidDescription$ each nonlegendary creature.
Oracle:Flying, lifelink\nAt the beginning of your upkeep, sacrifice Piru, the Volatile unless you pay {R}{W}{B}.\nWhen Piru dies, it deals 7 damage to each nonlegendary creature.

View File

@@ -0,0 +1,7 @@
Name:Priest of Fell Rites
ManaCost:W B
Types:Creature Human Warlock
PT:2/2
A:AB$ ChangeZone | Cost$ T PayLife<3> Sac<1/CARDNAME> | Origin$ Graveyard | Destination$ Battlefield | TgtPrompt$ Choose target creature card in your graveyard | ValidTgts$ Creature.YouCtrl | SorcerySpeed$ True | SpellDescription$ Return target creature card from your graveyard to the battlefield.
K:Unearth:3 W B
Oracle:{T}, Pay 3 life, Sacrifice Priest of Fell Rites: Return target creature card from your graveyard to the battlefield. Activate only as a sorcery.\nUnearth {3}{W}{B} ({3}{W}{B}: Return this card from your graveyard to the battlefield. It gains haste. Exile it at the beginning of the next end step or if it would leave the battlefield. Unearth only as a sorcery.)

View File

@@ -0,0 +1,12 @@
Name:Prophetic Titan
ManaCost:4 U R
Types:Creature Giant Wizard
PT:4/4
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigCharm | TriggerDescription$ Delirium — When CARDNAME enters the battlefield, choose one. If there are four or more card types in your graveyard, choose both.
SVar:TrigCharm:DB$ Charm | CharmNum$ X | Choices$ DBDealDamage,DBDig | AdditionalDescription$ If there are four or more card types in your graveyard, choose both.
SVar:DBDealDamage:DB$ DealDamage | ValidTgts$ Creature,Planeswalker,Player | TgtPrompt$ Select any target | NumDmg$ 4 | SpellDescription$ CARDNAME deals 4 damage to any target.
SVar:DBDig:DB$ Dig | DigNum$ 4 | RestRandomOrder$ True | SpellDescription$ Look at the top four cards of your library. Put one in your hand and the rest on the bottom of your library in a random order.
SVar:X:Count$Compare Y GE4.2.1
SVar:Y:Count$CardControllerTypes.Graveyard
SVar:PlayMain1:TRUE
Oracle:Delirium — When Prophetic Titan enters the battlefield, choose one. If there are four or more card types in your graveyard, choose both.\n• Prophetic Titan deals 4 damage to any target.\n• Look at the top four cards of your library. Put one in your hand and the rest on the bottom of your library in a random order.

View File

@@ -0,0 +1,7 @@
Name:Rift Sower
ManaCost:2 G
Types:Creature Elf Druid
PT:1/3
K:Suspend:2:G
A:AB$ Mana | Cost$ T | Produced$ Any | SpellDescription$ Add one mana of any color.
Oracle:{T}: Add one mana of any color.\nSuspend 2—{G} (Rather than cast this card from your hand, you may pay {G} and exile it with two time counters on it. At the beginning of your upkeep, remove a time counter. When the last is removed, cast it without paying its mana cost.)

View File

@@ -0,0 +1,16 @@
Name:Road
ManaCost:2 G
AlternateMode: Split
Types:Instant
A:SP$ ChangeZone | Cost$ 2 G | Origin$ Library | Destination$ Battlefield | ChangeType$ Land.Basic | ChangeNum$ 1 | Tapped$ True | SpellDescription$ Search your library for a basic land card, put it onto the battlefield tapped, then shuffle.
Oracle:Search your library for a basic land card, put it onto the battlefield tapped, then shuffle.
ALTERNATE
Name:Ruin
ManaCost:1 R R
Types:Sorcery
K:Aftermath
A:SP$ DealDamage | Cost$ 1 R R | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ X | SpellDescription$ CARDNAME deals damage to target creature equal to the number of lands you control.
SVar:X:Count$TypeYouCtrl.Land
Oracle:Ruin deals damage to target creature equal to the number of lands you control.

View File

@@ -0,0 +1,12 @@
Name:Sanctifier en-Vec
ManaCost:W W
Types:Creature Human Cleric
PT:2/2
K:Protection from black
K:Protection from red
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChangeZoneAll | TriggerDescription$ When CARDNAME enters the battlefield, exile all cards that are black or red from all graveyards.
SVar:TrigChangeZoneAll:DB$ ChangeZoneAll | ChangeType$ Card.Black,Card.Red | Origin$ Graveyard | Destination$ Exile
R:Event$ Moved | ActiveZones$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Black,Card.Red | ReplaceWith$ Exile | Description$ If a black or red permanent, spell, or card not on the battlefield would be put into a graveyard, exile it instead.
SVar:Exile:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Exile | Defined$ ReplacedCard
SVar:NonStackingEffect:True
Oracle:Protection from black and from red\nWhen Sanctifier en-Vec enters the battlefield, exile all cards that are black or red from all graveyards.\nIf a black or red permanent, spell, or card not on the battlefield would be put into a graveyard, exile it instead.

View File

@@ -0,0 +1,9 @@
Name:Sanctuary Raptor
ManaCost:3
Types:Artifact Creature Bird
PT:2/1
K:Flying
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigPump | IsPresent$ Permanent.token+YouCtrl | PresentCompare$ GE3 | TriggerDescription$ Whenever CARDNAME attacks, if you control three or more tokens, CARDNAME gets +2/+0 and gains first strike until end of turn.
SVar:TrigPump:DB$ Pump | Defined$ Self | NumAtt$ 2 | KW$ First Strike
DeckHints:Ability$Token
Oracle:Whenever Sanctuary Raptor attacks, if you control three or more tokens, Sanctuary Raptor gets +2/+0 and gains first strike until end of turn.

View File

@@ -0,0 +1,7 @@
Name:Sanctum Weaver
ManaCost:1 G
Types:Enchantment Creature Dryad
PT:0/2
A:AB$ Mana | Cost$ T | Produced$ Any | Amount$ X | SpellDescription$ Add X mana of any one color, where X is the number of enchantments you control.
SVar:X:Count$Valid Enchantment.YouCtrl
Oracle:{T}: Add X mana of any one color, where X is the number of enchantments you control.

View File

@@ -0,0 +1,10 @@
Name:Scurry Oak
ManaCost:2 G
Types:Creature Treefolk
PT:1/2
K:Evolve
T:Mode$ CounterAddedOnce | ValidCard$ Card.Self | TriggerZones$ Battlefield | CounterType$ P1P1 | OptionalDecider$ You | Execute$ TrigSquirrel | TriggerDescription$ Whenever one or more +1/+1 counters are put on CARDNAME, you may create a 1/1 green Squirrel creature token.
SVar:TrigSquirrel:DB$ Token | TokenAmount$ 1 | TokenScript$ g_1_1_squirrel | TokenOwner$ You
DeckHints:Ability$Counters
DeckHas:Ability$Token & Ability$Counters
Oracle:Evolve (Whenever a creature enters the battlefield under your control, if that creature has greater power or toughness than this creature, put a +1/+1 counter on this creature.)\nWhenever one or more +1/+1 counters are put on Scurry Oak, you may create a 1/1 green Squirrel creature token.

View File

@@ -0,0 +1,8 @@
Name:Shattered Ego
ManaCost:U
Types:Enchantment Aura
K:Enchant creature
A:SP$ Attach | Cost$ U | ValidTgts$ Creature | AILogic$ Curse
S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddPower$ -3 | Description$ Enchanted creature gets -3/-0.
A:AB$ ChangeZone | Cost$ 3 U U | Defined$ Enchanted | Origin$ Battlefield | Destination$ Library | LibraryPosition$ 2 | SpellDescription$ Put enchanted creature into its owner's library third from the top.
Oracle:Enchant creature\nEnchanted creature gets -3/-0.\n{3}{U}{U}: Put enchanted creature into its owner's library third from the top.

View File

@@ -0,0 +1,12 @@
Name:Steel Dromedary
ManaCost:3
Types:Artifact Creature Camel
PT:2/2
K:ETBReplacement:Other:CamelTapped
SVar:CamelTapped:DB$ Tap | Defined$ Self | ETB$ True | SubAbility$ DBAddCounter | SpellDescription$ CARDNAME enters the battlefield tapped with two +1/+1 counters on it.
SVar:DBAddCounter:DB$ PutCounter | ETB$ True | Defined$ Self | CounterType$ P1P1 | CounterNum$ 2
S:Mode$ Continuous | Affected$ Card.Self+counters_GE1_P1P1 | AddHiddenKeyword$ CARDNAME doesn't untap during your untap step. | Description$ As long as there are +1/+1 counters on CARDNAME, it doesn't untap during your untap step.
T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigMoveCounter | TriggerDescription$ At the beginning of combat on your turn, you may move a +1/+1 counter from CARDNAME onto another target creature.
SVar:TrigMoveCounter:DB$ MoveCounter | ValidTgts$ Creature.Other | TgtPrompt$ Select another target creature | Source$ Self | CounterType$ P1P1 | CounterNum$ 1
DeckHas:Ability$Counters
Oracle:Steel Dromedary enters the battlefield tapped with two +1/+1 counters on it.\nAs long as there are +1/+1 counters on Steel Dromedary, it doesn't untap during your untap step.\nAt the beginning of combat on your turn, you may move a +1/+1 counter from Steel Dromedary onto another target creature.

View File

@@ -0,0 +1,7 @@
Name:Strike It Rich
ManaCost:R
Types:Sorcery
K:Flashback:2 R
A:SP$ Token | TokenScript$ c_a_treasure_sac | SpellDescription$ Create a Treasure token. (It's an artifact with "{T}, Sacrifice this artifact: Add one mana of any color.")
DeckHas:Ability$Token & Ability$Sacrifice
Oracle:Create a Treasure token. (It's an artifact with "{T}, Sacrifice this artifact: Add one mana of any color.")\nFlashback {2}{R} (You may cast this card from your graveyard for its flashback cost. Then exile it.)

View File

@@ -0,0 +1,6 @@
Name:Sudden Edict
ManaCost:1 B
Types:Instant
K:Split second
A:SP$ Sacrifice | Cost$ 1 B | ValidTgts$ Player | SacValid$ Creature | SacMessage$ Creature | SpellDescription$ Target player sacrifices a creature.
Oracle:Split second (As long as this spell is on the stack, players can't cast spells or activate abilities that aren't mana abilities.)\nTarget player sacrifices a creature.

View File

@@ -0,0 +1,12 @@
Name:Sword of Hearth and Home
ManaCost:3
Types:Artifact Equipment
K:Equip:2
S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 2 | AddToughness$ 2 | AddSVar$ SwordOfHearthAndHomeCE | AddKeyword$ Protection from green & Protection from white | Description$ Equipped creature gets +2/+2 and has protection from green and from white.
T:Mode$ DamageDone | ValidSource$ Creature.EquippedBy | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigBlink | TriggerZones$ Battlefield | TriggerDescription$ Whenever equipped creature deals combat damage to a player, exile up to one target creature you own, then search your library for a basic land card. Put both cards onto the battlefield under your control, then shuffle.
SVar:TrigBlink:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | ValidTgts$ Creature.YouOwn | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Select target creature you own | SubAbility$ DBLand
SVar:DBLand:DB$ ChangeZone | Origin$ Library | Destination$ Library | ChangeType$ Land.Basic | ChangeNum$ 1 | RememberChanged$ True | SubAbility$ DBReturn
SVar:DBReturn:DB$ ChangeZone | Defined$ Remembered | Origin$ All | Destination$ Battlefield | GainControl$ True | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:SwordOfHearthAndHomeCE:SVar:MustBeBlocked:AttackingPlayerConservative
Oracle:Equipped creature gets +2/+2 and has protection from green and from white.\nWhenever equipped creature deals combat damage to a player, exile up to one target creature you own, then search your library for a basic land card. Put both cards onto the battlefield under your control, then shuffle.\nEquip {2}

View File

@@ -0,0 +1,7 @@
Name:Sylvan Anthem
ManaCost:G G
Types:Enchantment
S:Mode$ Continuous | Affected$ Creature.Green+YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Green creatures you control get +1/+1.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Green+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigScry | TriggerDescription$ Whenever a green creature enters the battlefield under your control, scry 1. (Look at the top card of your library. You may put that card on the bottom of your library.)
SVar:TrigScry:DB$ Scry | ScryNum$ 1
Oracle:Green creatures you control get +1/+1.\nWhenever a green creature enters the battlefield under your control, scry 1.

View File

@@ -0,0 +1,14 @@
Name:Territorial Kavu
ManaCost:R G
Types:Creature Kavu
PT:*/*
S:Mode$ Continuous | EffectZone$ All | CharacteristicDefining$ True | SetPower$ X | SetToughness$ X | Description$ Domain — CARDNAME's power and toughness are each equal to the number of basic land types among lands you control.
SVar:X:Count$Domain
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigCharm | TriggerDescription$ Whenever CARDNAME attacks, ABILITY
SVar:TrigCharm:DB$ Charm | Choices$ DBDiscard,DBExile
SVar:DBDiscard:DB$ Discard | NumCards$ 1 | Mode$ TgtChoose | RememberDiscarded$ True | SubAbility$ DBDraw | SpellDescription$ Discard a card. If you do, draw a card.
SVar:DBDraw:DB$ Draw | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ GE1 | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:DBExile:DB$ ChangeZone | ValidTgts$ Card | TgtPrompt$ Select up to one target card in a graveyard | TargetMin$ 0 | TargetMax$ 1 | Origin$ Graveyard | Destination$ Exile | SpellDescription$ Exile up to one target card from a graveyard.
DeckHas:Ability$Discard
Oracle:Domain — Territorial Kavu's power and toughness are each equal to the number of basic land types among lands you control.\nWhenever Territorial Kavu attacks, choose one —\n• Discard a card. If you do, draw a card.\n• Exile up to one target card from a graveyard.

View File

@@ -0,0 +1,9 @@
Name:Thraben Watcher
ManaCost:2 W W
Types:Creature Angel
PT:2/2
K:Flying
K:Vigilance
S:Mode$ Continuous | Affected$ Creature.nonToken+Other+YouCtrl | AddPower$ 1 | AddToughness$ 1 | AddKeyword$ Vigilance | Description$ Other nontoken creatures you control get +1/+1 and have vigilance.
SVar:PlayMain1:TRUE
Oracle:Flying, vigilance\nOther nontoken creatures you control get +1/+1 and have vigilance.

View File

@@ -0,0 +1,9 @@
Name:Timeless Witness
ManaCost:2 G G
Types:Creature Human Shaman
PT:2/1
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChangeZone | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may return target card from your graveyard to your hand.
SVar:TrigChangeZone:DB$ChangeZone | Origin$ Graveyard | Destination$ Hand | ValidTgts$ Card.YouCtrl
K:Eternalize:5 G G
DeckHas:Ability$Token
Oracle:When Eternal Witness enters the battlefield, you may return target card from your graveyard to your hand.\nEternalize {5}{G}{G} ({5}{G}{G}, Exile this card from your graveyard: Create a token that's a copy of it, except it's a 4/4 black Zombie Human Shaman with no mana cost. Eternalize only as a sorcery.)

View File

@@ -0,0 +1,8 @@
Name:Tormod's Cryptkeeper
ManaCost:3
Types:Artifact Creature Golem
PT:3/2
K:Vigilance
A:AB$ ChangeZoneAll | Cost$ T Sac<1/CARDNAME> | Origin$ Graveyard | Destination$ Exile | ValidTgts$ Player | TgtPrompt$ Select target player | ChangeType$ Card | SpellDescription$ Exile all cards from target player's graveyard.
AI:RemoveDeck:Random
Oracle:Vigilance\n{T}, Sacrifice Tormod's Cryptkeeper: Exile all cards from target player's graveyard.

View File

@@ -0,0 +1,9 @@
Name:Urban Daggertooth
ManaCost:2 G G
Types:Creature Dinosaur
PT:4/3
K:Vigilance
T:Mode$ DamageDoneOnce | Execute$ TrigProliferate | ValidTarget$ Card.Self | TriggerZones$ Battlefield | TriggerDescription$ Enrage — Whenever CARDNAME is dealt damage, proliferate.
SVar:TrigProliferate:DB$Proliferate
SVar:HasCombatEffect:TRUE
Oracle:Enrage — Whenever Urban Daggertooth is dealt damage, proliferate. (Choose any number of permanents and/or players, then give each another counter of each kind already there.)

View File

@@ -0,0 +1,6 @@
Name:Yavimaya, Cradle of Growth
ManaCost:no cost
Types:Legendary Land
S:Mode$ Continuous | Affected$ Land | AddType$ Forest | Description$ Each land is a Forest in addition to its other land types.
AI:RemoveDeck:Random
Oracle:Each land is a Forest in addition to its other land types.

View File

@@ -3,10 +3,9 @@ ManaCost:3 G G G
Types:Creature Elemental Incarnation Types:Creature Elemental Incarnation
PT:6/6 PT:6/6
K:Trample K:Trample
R:Event$ DamageDone | ActiveZones$ Battlefield | ValidTarget$ Creature.YouCtrl+Other | ReplaceWith$ Counters | PreventionEffect$ True | Description$ If damage would be dealt to another creature you control, prevent that damage. Put a +1/+1 counter on that creature for each 1 damage prevented this way. R:Event$ DamageDone | ActiveZones$ Battlefield | ValidTarget$ Creature.YouCtrl+Other | ReplaceWith$ Counters | PreventionEffect$ True | ExecuteMode$ PerTarget | Description$ If damage would be dealt to another creature you control, prevent that damage. Put a +1/+1 counter on that creature for each 1 damage prevented this way.
SVar:Counters:DB$PutCounter | Defined$ ReplacedTarget | CounterType$ P1P1 | CounterNum$ X SVar:Counters:DB$PutCounter | Defined$ ReplacedTarget | CounterType$ P1P1 | CounterNum$ X
SVar:X:ReplaceCount$DamageAmount SVar:X:ReplaceCount$DamageAmount
T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Creature.Self | Execute$ TrigShuffle | TriggerDescription$ When CARDNAME is put into a graveyard from anywhere, shuffle it into its owner's library. T:Mode$ ChangesZone | Origin$ Any | Destination$ Graveyard | ValidCard$ Creature.Self | Execute$ TrigShuffle | TriggerDescription$ When CARDNAME is put into a graveyard from anywhere, shuffle it into its owner's library.
SVar:TrigShuffle:DB$ ChangeZone | Origin$ Graveyard | Destination$ Library | Shuffle$ True | Defined$ TriggeredCardLKICopy SVar:TrigShuffle:DB$ ChangeZone | Origin$ Graveyard | Destination$ Library | Shuffle$ True | Defined$ TriggeredCardLKICopy
SVar:Picture:http://www.wizards.com/global/images/magic/general/vigor.jpg
Oracle:Trample\nIf damage would be dealt to another creature you control, prevent that damage. Put a +1/+1 counter on that creature for each 1 damage prevented this way.\nWhen Vigor is put into a graveyard from anywhere, shuffle it into its owner's library. Oracle:Trample\nIf damage would be dealt to another creature you control, prevent that damage. Put a +1/+1 counter on that creature for each 1 damage prevented this way.\nWhen Vigor is put into a graveyard from anywhere, shuffle it into its owner's library.

View File

@@ -320,6 +320,7 @@ Dack
Dakkon Dakkon
Daretti Daretti
Davriel Davriel
Dihada
Domri Domri
Dovin Dovin
Duck Duck