Merge branch 'timestampStateFix' into 'master'

Timestamp state fix

Closes #594 and #647

See merge request core-developers/forge!860
This commit is contained in:
Michael Kamensky
2018-08-21 20:26:42 +00:00
28 changed files with 157 additions and 115 deletions

View File

@@ -100,6 +100,7 @@ public class CountersMoveEffect extends SpellAbilityEffect {
// Test to see if the card we're trying to add is in the expected state // Test to see if the card we're trying to add is in the expected state
return; return;
} }
dest = cur;
int csum = 0; int csum = 0;
@@ -194,15 +195,15 @@ public class CountersMoveEffect extends SpellAbilityEffect {
Map<String, Object> params = Maps.newHashMap(); Map<String, Object> params = Maps.newHashMap();
params.put("CounterType", cType); params.put("CounterType", cType);
params.put("Source", source); params.put("Source", source);
params.put("Target", dest); params.put("Target", cur);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("Put how many ").append(cType.getName()).append(" counters on ").append(dest).append("?"); sb.append("Put how many ").append(cType.getName()).append(" counters on ").append(cur).append("?");
int cnum = player.getController().chooseNumber(sa, sb.toString(), 0, source.getCounters(cType), params); int cnum = player.getController().chooseNumber(sa, sb.toString(), 0, source.getCounters(cType), params);
if (cnum > 0) { if (cnum > 0) {
source.subtractCounter(cType, cnum); source.subtractCounter(cType, cnum);
dest.addCounter(cType, cnum, player, true); cur.addCounter(cType, cnum, player, true);
game.updateLastStateForCard(dest); game.updateLastStateForCard(cur);
updateSource = true; updateSource = true;
} }
} }
@@ -245,7 +246,7 @@ public class CountersMoveEffect extends SpellAbilityEffect {
} }
if (!"Any".matches(counterName)) { if (!"Any".matches(counterName)) {
if (!dest.canReceiveCounters(cType)) { if (!cur.canReceiveCounters(cType)) {
continue; continue;
} }
@@ -253,7 +254,7 @@ public class CountersMoveEffect extends SpellAbilityEffect {
Map<String, Object> params = Maps.newHashMap(); Map<String, Object> params = Maps.newHashMap();
params.put("CounterType", cType); params.put("CounterType", cType);
params.put("Source", source); params.put("Source", source);
params.put("Target", dest); params.put("Target", cur);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("Take how many ").append(cType.getName()); sb.append("Take how many ").append(cType.getName());
sb.append(" counters from ").append(source).append("?"); sb.append(" counters from ").append(source).append("?");
@@ -262,8 +263,8 @@ public class CountersMoveEffect extends SpellAbilityEffect {
if (source.getCounters(cType) >= cntToMove) { if (source.getCounters(cType) >= cntToMove) {
source.subtractCounter(cType, cntToMove); source.subtractCounter(cType, cntToMove);
dest.addCounter(cType, cntToMove, player, true); cur.addCounter(cType, cntToMove, player, true);
game.updateLastStateForCard(dest); game.updateLastStateForCard(cur);
} }
} else { } else {
// any counterType currently only Leech Bonder // any counterType currently only Leech Bonder

View File

@@ -135,9 +135,10 @@ public class CountersPutEffect extends SpellAbilityEffect {
for (final GameObject obj : tgtObjects) { for (final GameObject obj : tgtObjects) {
// check if the object is still in game or if it was moved // check if the object is still in game or if it was moved
Card gameCard = null;
if (obj instanceof Card) { if (obj instanceof Card) {
Card tgtCard = (Card) obj; Card tgtCard = (Card) obj;
Card gameCard = game.getCardState(tgtCard, null); gameCard = game.getCardState(tgtCard, null);
// gameCard is LKI in that case, the card is not in game anymore // gameCard is LKI in that case, the card is not in game anymore
// or the timestamp did change // or the timestamp did change
// this should check Self too // this should check Self too
@@ -164,7 +165,7 @@ public class CountersPutEffect extends SpellAbilityEffect {
((Player) obj).addCounter(ct, counterAmount, placer, true); ((Player) obj).addCounter(ct, counterAmount, placer, true);
} }
if (obj instanceof Card) { if (obj instanceof Card) {
((Card) obj).addCounter(ct, counterAmount, placer, true); gameCard.addCounter(ct, counterAmount, placer, true);
} }
} }
continue; continue;
@@ -185,7 +186,7 @@ public class CountersPutEffect extends SpellAbilityEffect {
} }
if (obj instanceof Card) { if (obj instanceof Card) {
Card tgtCard = (Card) obj; Card tgtCard = gameCard;
counterAmount = sa.usesTargeting() && sa.hasParam("DividedAsYouChoose") ? sa.getTargetRestrictions().getDividedValue(tgtCard) : counterAmount; counterAmount = sa.usesTargeting() && sa.hasParam("DividedAsYouChoose") ? sa.getTargetRestrictions().getDividedValue(tgtCard) : counterAmount;
if (!sa.usesTargeting() || tgtCard.canBeTargetedBy(sa)) { if (!sa.usesTargeting() || tgtCard.canBeTargetedBy(sa)) {
if (max != -1) { if (max != -1) {

View File

@@ -65,16 +65,16 @@ public class CountersPutOrRemoveEffect extends SpellAbilityEffect {
if (gameCard == null || !tgtCard.equalsWithTimestamp(gameCard)) { if (gameCard == null || !tgtCard.equalsWithTimestamp(gameCard)) {
continue; continue;
} }
if (!sa.usesTargeting() || tgtCard.canBeTargetedBy(sa)) { if (!sa.usesTargeting() || gameCard.canBeTargetedBy(sa)) {
if (tgtCard.hasCounters()) { if (gameCard.hasCounters()) {
if (sa.hasParam("EachExistingCounter")) { if (sa.hasParam("EachExistingCounter")) {
for (CounterType listType : Lists.newArrayList(tgtCard.getCounters().keySet())) { for (CounterType listType : Lists.newArrayList(gameCard.getCounters().keySet())) {
addOrRemoveCounter(sa, tgtCard, listType, counterAmount); addOrRemoveCounter(sa, gameCard, listType, counterAmount);
} }
} else { } else {
addOrRemoveCounter(sa, tgtCard, ctype, counterAmount); addOrRemoveCounter(sa, gameCard, ctype, counterAmount);
} }
game.updateLastStateForCard(tgtCard); game.updateLastStateForCard(gameCard);
} }
} }
} }

View File

@@ -115,27 +115,27 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
if (gameCard == null || !tgtCard.equalsWithTimestamp(gameCard)) { if (gameCard == null || !tgtCard.equalsWithTimestamp(gameCard)) {
continue; continue;
} }
if (!sa.usesTargeting() || tgtCard.canBeTargetedBy(sa)) { if (!sa.usesTargeting() || gameCard.canBeTargetedBy(sa)) {
final Zone zone = game.getZoneOf(gameCard); final Zone zone = game.getZoneOf(gameCard);
if (type.equals("All")) { if (type.equals("All")) {
for (Map.Entry<CounterType, Integer> e : tgtCard.getCounters().entrySet()) { for (Map.Entry<CounterType, Integer> e : gameCard.getCounters().entrySet()) {
tgtCard.subtractCounter(e.getKey(), e.getValue()); gameCard.subtractCounter(e.getKey(), e.getValue());
} }
game.updateLastStateForCard(tgtCard); game.updateLastStateForCard(gameCard);
continue; continue;
} else if (num.equals("All")) { } else if (num.equals("All")) {
cntToRemove = tgtCard.getCounters(counterType); cntToRemove = gameCard.getCounters(counterType);
} else if (sa.getParam("CounterNum").equals("Remembered")) { } else if (sa.getParam("CounterNum").equals("Remembered")) {
cntToRemove = tgtCard.getCountersAddedBy(card, counterType); cntToRemove = gameCard.getCountersAddedBy(card, counterType);
} }
PlayerController pc = sa.getActivatingPlayer().getController(); PlayerController pc = sa.getActivatingPlayer().getController();
if (type.equals("Any")) { if (type.equals("Any")) {
while (cntToRemove > 0 && tgtCard.hasCounters()) { while (cntToRemove > 0 && gameCard.hasCounters()) {
final Map<CounterType, Integer> tgtCounters = tgtCard.getCounters(); final Map<CounterType, Integer> tgtCounters = gameCard.getCounters();
Map<String, Object> params = Maps.newHashMap(); Map<String, Object> params = Maps.newHashMap();
params.put("Target", tgtCard); params.put("Target", gameCard);
String prompt = "Select type of counters to remove"; String prompt = "Select type of counters to remove";
CounterType chosenType = pc.chooseCounterType( CounterType chosenType = pc.chooseCounterType(
@@ -143,13 +143,13 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
prompt = "Select the number of " + chosenType.getName() + " counters to remove"; prompt = "Select the number of " + chosenType.getName() + " counters to remove";
int max = Math.min(cntToRemove, tgtCounters.get(chosenType)); int max = Math.min(cntToRemove, tgtCounters.get(chosenType));
params = Maps.newHashMap(); params = Maps.newHashMap();
params.put("Target", tgtCard); params.put("Target", gameCard);
params.put("CounterType", chosenType); params.put("CounterType", chosenType);
int chosenAmount = pc.chooseNumber(sa, prompt, 1, max, params); int chosenAmount = pc.chooseNumber(sa, prompt, 1, max, params);
if (chosenAmount > 0) { if (chosenAmount > 0) {
tgtCard.subtractCounter(chosenType, chosenAmount); gameCard.subtractCounter(chosenType, chosenAmount);
game.updateLastStateForCard(tgtCard); game.updateLastStateForCard(gameCard);
if (rememberRemoved) { if (rememberRemoved) {
for (int i = 0; i < chosenAmount; i++) { for (int i = 0; i < chosenAmount; i++) {
card.addRemembered(Pair.of(chosenType, i)); card.addRemembered(Pair.of(chosenType, i));
@@ -159,12 +159,12 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
} }
} }
} else { } else {
cntToRemove = Math.min(cntToRemove, tgtCard.getCounters(counterType)); cntToRemove = Math.min(cntToRemove, gameCard.getCounters(counterType));
if (zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Exile)) { if (zone.is(ZoneType.Battlefield) || zone.is(ZoneType.Exile)) {
if (sa.hasParam("UpTo")) { if (sa.hasParam("UpTo")) {
Map<String, Object> params = Maps.newHashMap(); Map<String, Object> params = Maps.newHashMap();
params.put("Target", tgtCard); params.put("Target", gameCard);
params.put("CounterType", type); params.put("CounterType", type);
String title = "Select the number of " + type + " counters to remove"; String title = "Select the number of " + type + " counters to remove";
cntToRemove = pc.chooseNumber(sa, title, 0, cntToRemove, params); cntToRemove = pc.chooseNumber(sa, title, 0, cntToRemove, params);
@@ -172,13 +172,13 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
} }
if (cntToRemove > 0) { if (cntToRemove > 0) {
tgtCard.subtractCounter(counterType, cntToRemove); gameCard.subtractCounter(counterType, cntToRemove);
if (rememberRemoved) { if (rememberRemoved) {
for (int i = 0; i < cntToRemove; i++) { for (int i = 0; i < cntToRemove; i++) {
card.addRemembered(Pair.of(counterType, i)); card.addRemembered(Pair.of(counterType, i));
} }
} }
game.updateLastStateForCard(tgtCard); game.updateLastStateForCard(gameCard);
} }
} }
} }

View File

@@ -1,6 +1,8 @@
package forge.game.ability.effects; package forge.game.ability.effects;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import forge.game.Game;
import forge.game.GameObject; import forge.game.GameObject;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.Card;
@@ -68,6 +70,7 @@ public class DamageDealEffect extends DamageBaseEffect {
@Override @Override
public void resolve(SpellAbility sa) { public void resolve(SpellAbility sa) {
final Card hostCard = sa.getHostCard(); final Card hostCard = sa.getHostCard();
final Game game = hostCard.getGame();
final String damage = sa.getParam("NumDmg"); final String damage = sa.getParam("NumDmg");
int dmg = AbilityUtils.calculateAmount(hostCard, damage, sa); int dmg = AbilityUtils.calculateAmount(hostCard, damage, sa);
@@ -176,7 +179,12 @@ public class DamageDealEffect extends DamageBaseEffect {
dmg = (sa.usesTargeting() && sa.hasParam("DividedAsYouChoose")) ? sa.getTargetRestrictions().getDividedValue(o) : dmg; dmg = (sa.usesTargeting() && sa.hasParam("DividedAsYouChoose")) ? sa.getTargetRestrictions().getDividedValue(o) : dmg;
if (o instanceof Card) { if (o instanceof Card) {
final Card c = (Card) o; final Card c = (Card) o;
if (c.isInPlay() && (!targeted || c.canBeTargetedBy(sa))) { final Card gc = game.getCardState(c, null);
if (gc == null || !c.equalsWithTimestamp(gc) || !gc.isInPlay()) {
// timestamp different or not in play
continue;
}
if (!targeted || c.canBeTargetedBy(sa)) {
if (removeDamage) { if (removeDamage) {
c.setDamage(0); c.setDamage(0);
c.setHasBeenDealtDeathtouchDamage(false); c.setHasBeenDealtDeathtouchDamage(false);

View File

@@ -86,7 +86,7 @@ public class FightEffect extends DamageBaseEffect {
defined.addAll(AbilityUtils.getDefinedCards(host, sa.getParam("ExtraDefined"), sa)); defined.addAll(AbilityUtils.getDefinedCards(host, sa.getParam("ExtraDefined"), sa));
} }
List<Card> remove = Lists.newArrayList(); List<Card> newDefined = Lists.newArrayList();
for (final Card d : defined) { for (final Card d : defined) {
final Card g = game.getCardState(d, null); final Card g = game.getCardState(d, null);
// 701.12b If a creature instructed to fight is no longer on the battlefield or is no longer a creature, // 701.12b If a creature instructed to fight is no longer on the battlefield or is no longer a creature,
@@ -94,10 +94,12 @@ public class FightEffect extends DamageBaseEffect {
// for a resolving spell or ability that instructs it to fight, no damage is dealt. // for a resolving spell or ability that instructs it to fight, no damage is dealt.
if (g == null || !g.equalsWithTimestamp(d) || !d.isInPlay() || !d.isCreature()) { if (g == null || !g.equalsWithTimestamp(d) || !d.isInPlay() || !d.isCreature()) {
// Test to see if the card we're trying to add is in the expected state // Test to see if the card we're trying to add is in the expected state
remove.add(d); continue;
} }
newDefined.add(g);
} }
defined.removeAll(remove); // replace with new List using CardState
defined = newDefined;
if (!defined.isEmpty()) { if (!defined.isEmpty()) {
if (defined.size() > 1 && fighter1 == null) { if (defined.size() > 1 && fighter1 == null) {

View File

@@ -12,7 +12,6 @@ import forge.game.event.GameEventCardStatsChanged;
import forge.game.keyword.KeywordInterface; import forge.game.keyword.KeywordInterface;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.Lang; import forge.util.Lang;
@@ -31,32 +30,40 @@ public class PumpEffect extends SpellAbilityEffect {
final int a, final int d, final List<String> keywords, final int a, final int d, final List<String> keywords,
final long timestamp) { final long timestamp) {
final Card host = sa.getHostCard(); final Card host = sa.getHostCard();
final Game game = host.getGame();
//if host is not on the battlefield don't apply //if host is not on the battlefield don't apply
// Suspend should does Affect the Stack // Suspend should does Affect the Stack
if (sa.hasParam("UntilLoseControlOfHost") if (sa.hasParam("UntilLoseControlOfHost")
&& !(host.isInPlay() || host.isInZone(ZoneType.Stack))) { && !(host.isInPlay() || host.isInZone(ZoneType.Stack))) {
return; return;
} }
final Game game = sa.getActivatingPlayer().getGame();
// do Game Check there in case of LKI
final Card gameCard = game.getCardState(applyTo, null);
if (gameCard == null || !applyTo.equalsWithTimestamp(gameCard)) {
return;
}
final List<String> kws = Lists.newArrayList(); final List<String> kws = Lists.newArrayList();
boolean redrawPT = false; boolean redrawPT = false;
for (String kw : keywords) { for (String kw : keywords) {
if (kw.startsWith("HIDDEN")) { if (kw.startsWith("HIDDEN")) {
applyTo.addHiddenExtrinsicKeyword(kw); gameCard.addHiddenExtrinsicKeyword(kw);
redrawPT |= kw.contains("CARDNAME's power and toughness are switched"); redrawPT |= kw.contains("CARDNAME's power and toughness are switched");
} else { } else {
kws.add(kw); kws.add(kw);
} }
} }
applyTo.addTempPowerBoost(a); gameCard.addTempPowerBoost(a);
applyTo.addTempToughnessBoost(d); gameCard.addTempToughnessBoost(d);
applyTo.addChangedCardKeywords(kws, Lists.<String>newArrayList(), false, false, timestamp); gameCard.addChangedCardKeywords(kws, Lists.<String>newArrayList(), false, false, timestamp);
if (redrawPT) { applyTo.updatePowerToughnessForView(); } if (redrawPT) {
gameCard.updatePowerToughnessForView();
}
if (sa.hasParam("LeaveBattlefield")) { if (sa.hasParam("LeaveBattlefield")) {
addLeaveBattlefieldReplacement(applyTo, sa, sa.getParam("LeaveBattlefield")); addLeaveBattlefieldReplacement(gameCard, sa, sa.getParam("LeaveBattlefield"));
} }
if (!sa.hasParam("Permanent")) { if (!sa.hasParam("Permanent")) {
@@ -66,8 +73,8 @@ public class PumpEffect extends SpellAbilityEffect {
@Override @Override
public void run() { public void run() {
applyTo.addTempPowerBoost(-1 * a); gameCard.addTempPowerBoost(-1 * a);
applyTo.addTempToughnessBoost(-1 * d); gameCard.addTempToughnessBoost(-1 * d);
if (keywords.size() > 0) { if (keywords.size() > 0) {
boolean redrawPT = false; boolean redrawPT = false;
@@ -75,16 +82,16 @@ public class PumpEffect extends SpellAbilityEffect {
for (String kw : keywords) { for (String kw : keywords) {
redrawPT |= kw.contains("CARDNAME's power and toughness are switched"); redrawPT |= kw.contains("CARDNAME's power and toughness are switched");
if (kw.startsWith("HIDDEN")) { if (kw.startsWith("HIDDEN")) {
applyTo.removeHiddenExtrinsicKeyword(kw); gameCard.removeHiddenExtrinsicKeyword(kw);
if (redrawPT) { if (redrawPT) {
applyTo.updatePowerToughnessForView(); gameCard.updatePowerToughnessForView();
} }
} }
} }
applyTo.removeChangedCardKeywords(timestamp); gameCard.removeChangedCardKeywords(timestamp);
} }
game.fireEvent(new GameEventCardStatsChanged(applyTo)); game.fireEvent(new GameEventCardStatsChanged(gameCard));
} }
}; };
if (sa.hasParam("UntilEndOfCombat")) { if (sa.hasParam("UntilEndOfCombat")) {
@@ -107,7 +114,7 @@ public class PumpEffect extends SpellAbilityEffect {
game.getEndOfTurn().addUntil(untilEOT); game.getEndOfTurn().addUntil(untilEOT);
} }
} }
game.fireEvent(new GameEventCardStatsChanged(applyTo)); game.fireEvent(new GameEventCardStatsChanged(gameCard));
} }
private static void applyPump(final SpellAbility sa, final Player p, private static void applyPump(final SpellAbility sa, final Player p,
@@ -218,7 +225,6 @@ public class PumpEffect extends SpellAbilityEffect {
public void resolve(final SpellAbility sa) { public void resolve(final SpellAbility sa) {
final List<Card> untargetedCards = Lists.newArrayList(); final List<Card> untargetedCards = Lists.newArrayList();
final TargetRestrictions tgt = sa.getTargetRestrictions();
final Game game = sa.getActivatingPlayer().getGame(); final Game game = sa.getActivatingPlayer().getGame();
final Card host = sa.getHostCard(); final Card host = sa.getHostCard();
final long timestamp = game.getNextTimestamp(); final long timestamp = game.getNextTimestamp();
@@ -350,7 +356,7 @@ public class PumpEffect extends SpellAbilityEffect {
} }
// if pump is a target, make sure we can still target now // if pump is a target, make sure we can still target now
if ((tgt != null) && !tgtC.canBeTargetedBy(sa)) { if (sa.usesTargeting() && !tgtC.canBeTargetedBy(sa)) {
continue; continue;
} }

View File

@@ -4872,7 +4872,7 @@ public class Card extends GameEntity implements Comparable<Card> {
timestamp = t; timestamp = t;
} }
public boolean equalsWithTimestamp(Card c) { public boolean equalsWithTimestamp(Card c) {
return c == this && c.getTimestamp() == timestamp; return equals(c) && c.getTimestamp() == timestamp;
} }
/** /**

View File

@@ -2362,7 +2362,7 @@ public class CardFactoryUtil {
+ "TriggerZones$ Battlefield | Secondary$ True | TriggerDescription$ " + "TriggerZones$ Battlefield | Secondary$ True | TriggerDescription$ "
+ "Exalted (" + inst.getReminderText() + ")"; + "Exalted (" + inst.getReminderText() + ")";
final String effect = "DB$ Pump | Defined$ TriggeredAttacker | NumAtt$ +1 | NumDef$ +1"; final String effect = "DB$ Pump | Defined$ TriggeredAttackerLKICopy | NumAtt$ +1 | NumDef$ +1";
final Trigger trigger = TriggerHandler.parseTrigger(trig, card, intrinsic); final Trigger trigger = TriggerHandler.parseTrigger(trig, card, intrinsic);
trigger.setOverridingAbility(AbilityFactory.getAbility(effect, card)); trigger.setOverridingAbility(AbilityFactory.getAbility(effect, card));
@@ -2441,7 +2441,7 @@ public class CardFactoryUtil {
" | TriggerZones$ Battlefield | Secondary$ True " + " | TriggerZones$ Battlefield | Secondary$ True " +
" | TriggerDescription$ Flanking (" + inst.getReminderText() + ")"); " | TriggerDescription$ Flanking (" + inst.getReminderText() + ")");
final String effect = "DB$ Pump | Defined$ TriggeredBlocker | NumAtt$ -1 | NumDef$ -1"; final String effect = "DB$ Pump | Defined$ TriggeredBlockerLKICopy | NumAtt$ -1 | NumDef$ -1";
final Trigger trigger = TriggerHandler.parseTrigger(trigFlanking.toString(), card, intrinsic); final Trigger trigger = TriggerHandler.parseTrigger(trigFlanking.toString(), card, intrinsic);
trigger.setOverridingAbility(AbilityFactory.getAbility(effect, card)); trigger.setOverridingAbility(AbilityFactory.getAbility(effect, card));
@@ -2645,7 +2645,7 @@ public class CardFactoryUtil {
final String trigStr = "Mode$ Attacks | ValidCard$ Card.Self | Secondary$ True " + final String trigStr = "Mode$ Attacks | ValidCard$ Card.Self | Secondary$ True " +
" | TriggerDescription$ Melee (" + inst.getReminderText() + ")"; " | TriggerDescription$ Melee (" + inst.getReminderText() + ")";
final String effect = "DB$ Pump | Defined$ TriggeredAttacker | NumAtt$ MeleeX | NumDef$ MeleeX"; final String effect = "DB$ Pump | Defined$ TriggeredAttackerLKICopy | NumAtt$ MeleeX | NumDef$ MeleeX";
final Trigger trigger = TriggerHandler.parseTrigger(trigStr.toString(), card, intrinsic); final Trigger trigger = TriggerHandler.parseTrigger(trigStr.toString(), card, intrinsic);
SpellAbility sa = AbilityFactory.getAbility(effect, card); SpellAbility sa = AbilityFactory.getAbility(effect, card);
@@ -2818,7 +2818,7 @@ public class CardFactoryUtil {
" | ValidBlocker$ Creature | MinBlockers$ 1 | Secondary$ True " + " | ValidBlocker$ Creature | MinBlockers$ 1 | Secondary$ True " +
" | TriggerDescription$ Rampage " + n + " (" + inst.getReminderText() + ")"; " | TriggerDescription$ Rampage " + n + " (" + inst.getReminderText() + ")";
final String effect = "DB$ Pump | Defined$ TriggeredAttacker" + final String effect = "DB$ Pump | Defined$ TriggeredAttackerLKICopy" +
" | NumAtt$ Rampage" + n + " | NumDef$ Rampage" + n; " | NumAtt$ Rampage" + n + " | NumDef$ Rampage" + n;
final Trigger trigger = TriggerHandler.parseTrigger(trigStr.toString(), card, intrinsic); final Trigger trigger = TriggerHandler.parseTrigger(trigStr.toString(), card, intrinsic);

View File

@@ -283,6 +283,8 @@ public final class CardUtil {
newCopy.setMeldedWith(in.getMeldedWith()); newCopy.setMeldedWith(in.getMeldedWith());
newCopy.setTimestamp(in.getTimestamp());
// update keyword cache on all states // update keyword cache on all states
for (CardStateName s : newCopy.getStates()) { for (CardStateName s : newCopy.getStates()) {
newCopy.updateKeywordsCache(newCopy.getState(s)); newCopy.updateKeywordsCache(newCopy.getState(s));

View File

@@ -209,10 +209,10 @@ public class WrappedAbility extends Ability {
// a real solution would include only the triggering information that actually is used, but that's a major change // a real solution would include only the triggering information that actually is used, but that's a major change
@Override @Override
public String toUnsuppressedString() { public String toUnsuppressedString() {
String desc = this.getStackDescription(); /* use augmented stack description as string for wrapped things */ String desc = this.getStackDescription(); /* use augmented stack description as string for wrapped things */
String card = getTrigger().getHostCard().toString(); String card = getTrigger().getHostCard().toString();
if ( !desc.contains(card) && desc.contains(" this ")) { /* a hack for Evolve and similar that don't have CARDNAME */ if ( !desc.contains(card) && desc.contains(" this ")) { /* a hack for Evolve and similar that don't have CARDNAME */
return card + ": " + desc; return card + ": " + desc;
} else return desc; } else return desc;
} }
@@ -476,34 +476,9 @@ public class WrappedAbility extends Ability {
return; return;
} }
// Check timestamps of triggered objects if (!triggerParams.containsKey("NoTimestampCheck")) {
final List<Object> original = Lists.newArrayList(sa.getTriggerRemembered()); timestampCheck();
for (Object o : original) {
if (o instanceof Card) {
Card card = (Card) o;
Card current = game.getCardState(card);
if (current.getTimestamp() != card.getTimestamp()) {
// TODO: figure out if NoTimestampCheck should be the default for ChangesZone triggers
if (!triggerParams.containsKey("NoTimestampCheck")) {
sa.getTriggerRemembered().remove(o);
}
}
}
} }
final Map<String, Object> triggerMap = new HashMap<String, Object>(sa.getTriggeringObjects());
for (Entry<String, Object> ev : triggerMap.entrySet()) {
if (ev.getValue() instanceof Card) {
Card card = (Card) ev.getValue();
Card current = game.getCardState(card);
if (card.isInPlay() && current.isInPlay() && current.getTimestamp() != card.getTimestamp()) {
// TODO: figure out if NoTimestampCheck should be the default for ChangesZone triggers
if (!triggerParams.containsKey("NoTimestampCheck")) {
sa.getTriggeringObjects().remove(ev.getKey());
}
}
}
}
// TODO: CardCollection
getActivatingPlayer().getController().playSpellAbilityNoStack(sa, false); getActivatingPlayer().getController().playSpellAbilityNoStack(sa, false);
@@ -516,4 +491,50 @@ public class WrappedAbility extends Ability {
th.registerDelayedTrigger(deltrig); th.registerDelayedTrigger(deltrig);
} }
} }
}
/**
* TODO remove this function after the Effects are updated
*/
protected void timestampCheck() {
final Game game = sa.getActivatingPlayer().getGame();
if (ApiType.PutCounter.equals(sa.getApi())
|| ApiType.MoveCounter.equals(sa.getApi())
|| ApiType.MultiplyCounter.equals(sa.getApi())
|| ApiType.MoveCounter.equals(sa.getApi())
|| ApiType.RemoveCounter.equals(sa.getApi())
|| ApiType.AddOrRemoveCounter.equals(sa.getApi())
|| ApiType.MoveCounter.equals(sa.getApi())
// Token has no Defined it should not be timestamp problems
|| ApiType.Token.equals(sa.getApi())
) {
return;
}
// Check timestamps of triggered objects
final List<Object> original = Lists.newArrayList(sa.getTriggerRemembered());
for (Object o : original) {
if (o instanceof Card) {
Card card = (Card) o;
Card current = game.getCardState(card);
if (current.getTimestamp() != card.getTimestamp()) {
// TODO: figure out if NoTimestampCheck should be the default for ChangesZone triggers
sa.getTriggerRemembered().remove(o);
}
}
}
final Map<String, Object> triggerMap = new HashMap<String, Object>(sa.getTriggeringObjects());
for (Entry<String, Object> ev : triggerMap.entrySet()) {
if (ev.getValue() instanceof Card) {
Card card = (Card) ev.getValue();
Card current = game.getCardState(card);
if (card.isInPlay() && current.isInPlay() && current.getTimestamp() != card.getTimestamp()) {
// TODO: figure out if NoTimestampCheck should be the default for ChangesZone triggers
sa.getTriggeringObjects().remove(ev.getKey());
}
}
}
// TODO: CardCollection
}
}

View File

@@ -4,7 +4,7 @@ Types:Creature Human Monk
PT:3/1 PT:3/1
K:Renown:1 K:Renown:1
T:Mode$ AttackerBlockedByCreature | ValidCard$ Card.Self | ValidBlocker$ Creature | Execute$ TrigDealDamage | TriggerDescription$ Whenever CARDNAME becomes blocked by a creature, it deals 2 damage to that creature. T:Mode$ AttackerBlockedByCreature | ValidCard$ Card.Self | ValidBlocker$ Creature | Execute$ TrigDealDamage | TriggerDescription$ Whenever CARDNAME becomes blocked by a creature, it deals 2 damage to that creature.
SVar:TrigDealDamage:DB$ DealDamage | Defined$ TriggeredBlocker | NumDmg$ 2 SVar:TrigDealDamage:DB$ DealDamage | Defined$ TriggeredBlockerLKICopy | NumDmg$ 2
DeckHas:Ability$Counters DeckHas:Ability$Counters
SVar:Picture:http://www.wizards.com/global/images/magic/general/acolyte_of_the_inferno.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/acolyte_of_the_inferno.jpg
Oracle:Renown 1 (When this creature deals combat damage to a player, if it isn't renowned, put a +1/+1 counter on it and it becomes renowned.)\nWhenever Acolyte of the Inferno becomes blocked by a creature, it deals 2 damage to that creature. Oracle:Renown 1 (When this creature deals combat damage to a player, if it isn't renowned, put a +1/+1 counter on it and it becomes renowned.)\nWhenever Acolyte of the Inferno becomes blocked by a creature, it deals 2 damage to that creature.

View File

@@ -2,7 +2,7 @@ Name:Aether Flash
ManaCost:2 R R ManaCost:2 R R
Types:Enchantment Types:Enchantment
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature | TriggerZones$ Battlefield | Execute$ TrigDealDamage | TriggerDescription$ Whenever a creature enters the battlefield, CARDNAME deals 2 damage to it. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature | TriggerZones$ Battlefield | Execute$ TrigDealDamage | TriggerDescription$ Whenever a creature enters the battlefield, CARDNAME deals 2 damage to it.
SVar:TrigDealDamage:DB$DealDamage | Defined$ TriggeredCard | NumDmg$ 2 SVar:TrigDealDamage:DB$DealDamage | Defined$ TriggeredCardLKICopy | NumDmg$ 2
SVar:RemRandomDeck:True SVar:RemRandomDeck:True
SVar:Picture:http://www.wizards.com/global/images/magic/general/aether_flash.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/aether_flash.jpg
Oracle:Whenever a creature enters the battlefield, Aether Flash deals 2 damage to it. Oracle:Whenever a creature enters the battlefield, Aether Flash deals 2 damage to it.

View File

@@ -4,7 +4,7 @@ Types:Creature Elemental Hound
PT:2/1 PT:2/1
T:Mode$ AttackerBlockedByCreature | ValidCard$ Creature | ValidBlocker$ Card.Self | Execute$ TrigDamageAttacker | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 1 damage to that creature. T:Mode$ AttackerBlockedByCreature | ValidCard$ Creature | ValidBlocker$ Card.Self | Execute$ TrigDamageAttacker | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 1 damage to that creature.
T:Mode$ AttackerBlockedByCreature | ValidCard$ Card.Self | ValidBlocker$ Creature | Execute$ TrigDamageBlocker | Secondary$ True | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 1 damage to that creature. T:Mode$ AttackerBlockedByCreature | ValidCard$ Card.Self | ValidBlocker$ Creature | Execute$ TrigDamageBlocker | Secondary$ True | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 1 damage to that creature.
SVar:TrigDamageAttacker:DB$ DealDamage | Defined$ TriggeredAttacker | NumDmg$ 1 SVar:TrigDamageAttacker:DB$ DealDamage | Defined$ TriggeredAttackerLKICopy | NumDmg$ 1
SVar:TrigDamageBlocker:DB$ DealDamage | Defined$ TriggeredBlocker | NumDmg$ 1 SVar:TrigDamageBlocker:DB$ DealDamage | Defined$ TriggeredBlockerLKICopy | NumDmg$ 1
SVar:Picture:http://www.wizards.com/global/images/magic/general/ashmouth_hound.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/ashmouth_hound.jpg
Oracle:Whenever Ashmouth Hound blocks or becomes blocked by a creature, Ashmouth Hound deals 1 damage to that creature. Oracle:Whenever Ashmouth Hound blocks or becomes blocked by a creature, Ashmouth Hound deals 1 damage to that creature.

View File

@@ -4,10 +4,10 @@ Types:Creature Wolf
PT:5/5 PT:5/5
T:Mode$ AttackerBlockedByCreature | ValidCard$ Creature | ValidBlocker$ Card.Self | Execute$ TrigDamageAttacker | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 3 damage to that creature and 3 damage to that creature's controller. T:Mode$ AttackerBlockedByCreature | ValidCard$ Creature | ValidBlocker$ Card.Self | Execute$ TrigDamageAttacker | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 3 damage to that creature and 3 damage to that creature's controller.
T:Mode$ AttackerBlockedByCreature | ValidCard$ Card.Self | ValidBlocker$ Creature | Execute$ TrigDamageBlocker | Secondary$ True | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 3 damage to that creature and 3 damage to that creature's controller. T:Mode$ AttackerBlockedByCreature | ValidCard$ Card.Self | ValidBlocker$ Creature | Execute$ TrigDamageBlocker | Secondary$ True | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 3 damage to that creature and 3 damage to that creature's controller.
SVar:TrigDamageAttacker:DB$ DealDamage | Defined$ TriggeredAttacker | NumDmg$ 3 | SubAbility$ DBDamageAtk SVar:TrigDamageAttacker:DB$ DealDamage | Defined$ TriggeredAttackerLKICopy | NumDmg$ 3 | SubAbility$ DBDamageAtk
SVar:TrigDamageBlocker:DB$ DealDamage | Defined$ TriggeredBlocker | NumDmg$ 3 | SubAbility$ DBDamageBlk SVar:TrigDamageBlocker:DB$ DealDamage | Defined$ TriggeredBlockerLKICopy | NumDmg$ 3 | SubAbility$ DBDamageBlk
SVar:DBDamageAtk:DB$ DealDamage | Defined$ TriggeredAttackerController | NumDmg$ 3 SVar:DBDamageAtk:DB$ DealDamage | Defined$ TriggeredAttackerController | NumDmg$ 3
SVar:DBDamageBlk:DB$ DealDamage | Defined$ TriggeredBlockerController | NumDmg$ 3 SVar:DBDamageBlk:DB$ DealDamage | Defined$ TriggeredBlockerController | NumDmg$ 3
SVar:HasCombatEffect:TRUE SVar:HasCombatEffect:TRUE
SVar:Picture:http://www.wizards.com/global/images/magic/general/assembled_alphas.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/assembled_alphas.jpg
Oracle:Whenever Assembled Alphas blocks or becomes blocked by a creature, Assembled Alphas deals 3 damage to that creature and 3 damage to that creature's controller. Oracle:Whenever Assembled Alphas blocks or becomes blocked by a creature, Assembled Alphas deals 3 damage to that creature and 3 damage to that creature's controller.

View File

@@ -2,7 +2,7 @@ Name:Caltrops
ManaCost:3 ManaCost:3
Types:Artifact Types:Artifact
T:Mode$ Attacks | ValidCard$ Creature | TriggerZones$ Battlefield | Execute$ TrigDamage | TriggerDescription$ Whenever a creature attacks, CARDNAME deals 1 damage to it. T:Mode$ Attacks | ValidCard$ Creature | TriggerZones$ Battlefield | Execute$ TrigDamage | TriggerDescription$ Whenever a creature attacks, CARDNAME deals 1 damage to it.
SVar:TrigDamage:DB$DealDamage | Defined$ TriggeredAttacker | NumDmg$ 1 SVar:TrigDamage:DB$DealDamage | Defined$ TriggeredAttackerLKICopy | NumDmg$ 1
SVar:RemRandomDeck:True SVar:RemRandomDeck:True
SVar:Picture:http://www.wizards.com/global/images/magic/general/caltrops.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/caltrops.jpg
Oracle:Whenever a creature attacks, Caltrops deals 1 damage to it. Oracle:Whenever a creature attacks, Caltrops deals 1 damage to it.

View File

@@ -2,6 +2,6 @@ Name:Circle of Flame
ManaCost:1 R ManaCost:1 R
Types:Enchantment Types:Enchantment
T:Mode$ Attacks | ValidCard$ Creature.withoutFlying | Attacked$ You,Planeswalker.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDamage | TriggerDescription$ Whenever a creature without flying attacks you or a planeswalker you control, CARDNAME deals 1 damage to that creature. T:Mode$ Attacks | ValidCard$ Creature.withoutFlying | Attacked$ You,Planeswalker.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDamage | TriggerDescription$ Whenever a creature without flying attacks you or a planeswalker you control, CARDNAME deals 1 damage to that creature.
SVar:TrigDamage:DB$ DealDamage | Defined$ TriggeredAttacker | NumDmg$ 1 SVar:TrigDamage:DB$ DealDamage | Defined$ TriggeredAttackerLKICopy | NumDmg$ 1
SVar:Picture:http://www.wizards.com/global/images/magic/general/circle_of_flame.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/circle_of_flame.jpg
Oracle:Whenever a creature without flying attacks you or a planeswalker you control, Circle of Flame deals 1 damage to that creature. Oracle:Whenever a creature without flying attacks you or a planeswalker you control, Circle of Flame deals 1 damage to that creature.

View File

@@ -4,7 +4,8 @@ Types:Creature Elemental Scout
PT:2/4 PT:2/4
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Other |TriggerZones$ Battlefield | Execute$ TrigSac | TriggerDescription$ When another creature enters the battlefield, sacrifice Flame-Kin War Scout. If you do, Flame-Kin War Scout deals 4 damage to that creature. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Other |TriggerZones$ Battlefield | Execute$ TrigSac | TriggerDescription$ When another creature enters the battlefield, sacrifice Flame-Kin War Scout. If you do, Flame-Kin War Scout deals 4 damage to that creature.
SVar:TrigSac:DB$Sacrifice | Defined$ Self | SubAbility$ DBDamage | RememberSacrificed$ True SVar:TrigSac:DB$Sacrifice | Defined$ Self | SubAbility$ DBDamage | RememberSacrificed$ True
SVar:DBDamage:DB$DealDamage | Defined$ TriggeredCard | NumDmg$ 4 | ConditionDefined$ Remembered | ConditionPresent$ Card.Self SVar:DBDamage:DB$DealDamage | Defined$ TriggeredCardLKICopy | NumDmg$ 4 | ConditionDefined$ Remembered | ConditionPresent$ Card.Self | SubAbility$ DBCleanup
SVar:DBCleanup:DB$Cleanup | ClearRemembered$ True
SVar:RemAIDeck:True SVar:RemAIDeck:True
SVar:Picture:http://www.wizards.com/global/images/magic/general/flame_kin_war_scout.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/flame_kin_war_scout.jpg
Oracle:When another creature enters the battlefield, sacrifice Flame-Kin War Scout. If you do, Flame-Kin War Scout deals 4 damage to that creature. Oracle:When another creature enters the battlefield, sacrifice Flame-Kin War Scout. If you do, Flame-Kin War Scout deals 4 damage to that creature.

View File

@@ -4,7 +4,7 @@ Types:Enchantment Aura
K:Enchant creature K:Enchant creature
A:SP$ Attach | Cost$ W | ValidTgts$ Creature | AILogic$ SpecificCard A:SP$ Attach | Cost$ W | ValidTgts$ Creature | AILogic$ SpecificCard
T:Mode$ DamageDealtOnce | ValidSource$ Card.AttachedBy | Execute$ TrigDamage | TriggerZones$ Battlefield | TriggerDescription$ Whenever enchanted creature deals damage, CARDNAME deals that much damage to that creature. T:Mode$ DamageDealtOnce | ValidSource$ Card.AttachedBy | Execute$ TrigDamage | TriggerZones$ Battlefield | TriggerDescription$ Whenever enchanted creature deals damage, CARDNAME deals that much damage to that creature.
SVar:TrigDamage:DB$ DealDamage | Defined$ TriggeredSource | NumDmg$ X | References$ X SVar:TrigDamage:DB$ DealDamage | Defined$ TriggeredSourceLKICopy | NumDmg$ X | References$ X
SVar:X:TriggerCount$DamageAmount SVar:X:TriggerCount$DamageAmount
SVar:Picture:http://www.wizards.com/global/images/magic/general/guilty_conscience.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/guilty_conscience.jpg
Oracle:Enchant creature\nWhenever enchanted creature deals damage, Guilty Conscience deals that much damage to that creature. Oracle:Enchant creature\nWhenever enchanted creature deals damage, Guilty Conscience deals that much damage to that creature.

View File

@@ -4,7 +4,7 @@ Types:Creature Elemental
PT:4/4 PT:4/4
T:Mode$ AttackerBlockedByCreature | ValidCard$ Creature | ValidBlocker$ Card.Self | Execute$ TrigDealDamageAttack | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 3 damage to that creature. T:Mode$ AttackerBlockedByCreature | ValidCard$ Creature | ValidBlocker$ Card.Self | Execute$ TrigDealDamageAttack | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 3 damage to that creature.
T:Mode$ AttackerBlockedByCreature | ValidCard$ Card.Self | ValidBlocker$ Creature | Execute$ TrigDealDamageBlock | Secondary$ True | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 3 damage to that creature. T:Mode$ AttackerBlockedByCreature | ValidCard$ Card.Self | ValidBlocker$ Creature | Execute$ TrigDealDamageBlock | Secondary$ True | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 3 damage to that creature.
SVar:TrigDealDamageAttack:DB$DealDamage | Defined$ TriggeredAttacker | NumDmg$ 3 SVar:TrigDealDamageAttack:DB$DealDamage | Defined$ TriggeredAttackerLKICopy | NumDmg$ 3
SVar:TrigDealDamageBlock:DB$DealDamage | Defined$ TriggeredBlocker | NumDmg$ 3 SVar:TrigDealDamageBlock:DB$DealDamage | Defined$ TriggeredBlockerLKICopy | NumDmg$ 3
SVar:Picture:http://www.wizards.com/global/images/magic/general/inferno_elemental.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/inferno_elemental.jpg
Oracle:Whenever Inferno Elemental blocks or becomes blocked by a creature, Inferno Elemental deals 3 damage to that creature. Oracle:Whenever Inferno Elemental blocks or becomes blocked by a creature, Inferno Elemental deals 3 damage to that creature.

View File

@@ -4,8 +4,8 @@ Types:Creature Human Shaman Werewolf
PT:2/1 PT:2/1
T:Mode$ AttackerBlockedByCreature | ValidCard$ Creature | ValidBlocker$ Card.Self | Execute$ TrigDamageAttacker | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 1 damage to that creature. T:Mode$ AttackerBlockedByCreature | ValidCard$ Creature | ValidBlocker$ Card.Self | Execute$ TrigDamageAttacker | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 1 damage to that creature.
T:Mode$ AttackerBlockedByCreature | ValidCard$ Card.Self | ValidBlocker$ Creature | Execute$ TrigDamageBlocker | Secondary$ True | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 1 damage to that creature. T:Mode$ AttackerBlockedByCreature | ValidCard$ Card.Self | ValidBlocker$ Creature | Execute$ TrigDamageBlocker | Secondary$ True | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 1 damage to that creature.
SVar:TrigDamageAttacker:DB$ DealDamage | Defined$ TriggeredAttacker | NumDmg$ 1 SVar:TrigDamageAttacker:DB$ DealDamage | Defined$ TriggeredAttackerLKICopy | NumDmg$ 1
SVar:TrigDamageBlocker:DB$ DealDamage | Defined$ TriggeredBlocker | NumDmg$ 1 SVar:TrigDamageBlocker:DB$ DealDamage | Defined$ TriggeredBlockerLKICopy | NumDmg$ 1
T:Mode$Phase | Phase$ Upkeep | WerewolfTransformCondition$ True | TriggerZones$ Battlefield | Execute$ TrigTransform | TriggerDescription$ At the beginning of each upkeep, if no spells were cast last turn, transform CARDNAME. T:Mode$Phase | Phase$ Upkeep | WerewolfTransformCondition$ True | TriggerZones$ Battlefield | Execute$ TrigTransform | TriggerDescription$ At the beginning of each upkeep, if no spells were cast last turn, transform CARDNAME.
SVar:TrigTransform:DB$SetState | Defined$ Self | Mode$ Transform SVar:TrigTransform:DB$SetState | Defined$ Self | Mode$ Transform
AlternateMode:DoubleFaced AlternateMode:DoubleFaced
@@ -21,8 +21,8 @@ Types:Creature Werewolf
PT:3/2 PT:3/2
T:Mode$ AttackerBlockedByCreature | ValidCard$ Creature | ValidBlocker$ Card.Self | Execute$ TrigDamageAttacker | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 2 damage to that creature. T:Mode$ AttackerBlockedByCreature | ValidCard$ Creature | ValidBlocker$ Card.Self | Execute$ TrigDamageAttacker | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 2 damage to that creature.
T:Mode$ AttackerBlockedByCreature | ValidCard$ Card.Self | ValidBlocker$ Creature | Execute$ TrigDamageBlocker | Secondary$ True | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 2 damage to that creature. T:Mode$ AttackerBlockedByCreature | ValidCard$ Card.Self | ValidBlocker$ Creature | Execute$ TrigDamageBlocker | Secondary$ True | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, CARDNAME deals 2 damage to that creature.
SVar:TrigDamageAttacker:DB$ DealDamage | Defined$ TriggeredAttacker | NumDmg$ 2 SVar:TrigDamageAttacker:DB$ DealDamage | Defined$ TriggeredAttackerLKICopy | NumDmg$ 2
SVar:TrigDamageBlocker:DB$ DealDamage | Defined$ TriggeredBlocker | NumDmg$ 2 SVar:TrigDamageBlocker:DB$ DealDamage | Defined$ TriggeredBlockerLKICopy | NumDmg$ 2
T:Mode$Phase | Phase$ Upkeep | WerewolfUntransformCondition$ True | TriggerZones$ Battlefield | Execute$ TrigTransform | TriggerDescription$ At the beginning of each upkeep, if a player cast two or more spells last turn, transform CARDNAME. T:Mode$Phase | Phase$ Upkeep | WerewolfUntransformCondition$ True | TriggerZones$ Battlefield | Execute$ TrigTransform | TriggerDescription$ At the beginning of each upkeep, if a player cast two or more spells last turn, transform CARDNAME.
SVar:TrigTransform:DB$SetState | Defined$ Self | Mode$ Transform SVar:TrigTransform:DB$SetState | Defined$ Self | Mode$ Transform
SVar:Picture:http://www.wizards.com/global/images/magic/general/flameheart_werewolf.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/flameheart_werewolf.jpg

View File

@@ -3,6 +3,6 @@ ManaCost:1 R
Types:Creature Human Warrior Types:Creature Human Warrior
PT:2/1 PT:2/1
T:Mode$ AttackerBlockedByCreature | ValidCard$ Card.Self | ValidBlocker$ Creature | Execute$ TrigDamage | TriggerDescription$ Whenever CARDNAME becomes blocked by a creature, CARDNAME deals 1 damage to that creature. T:Mode$ AttackerBlockedByCreature | ValidCard$ Card.Self | ValidBlocker$ Creature | Execute$ TrigDamage | TriggerDescription$ Whenever CARDNAME becomes blocked by a creature, CARDNAME deals 1 damage to that creature.
SVar:TrigDamage:DB$ DealDamage | Defined$ TriggeredBlocker | NumDmg$ 1 SVar:TrigDamage:DB$ DealDamage | Defined$ TriggeredBlockerLKICopy | NumDmg$ 1
SVar:Picture:http://www.wizards.com/global/images/magic/general/kolaghan_aspirant.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/kolaghan_aspirant.jpg
Oracle:Whenever Kolaghan Aspirant becomes blocked by a creature, Kolaghan Aspirant deals 1 damage to that creature. Oracle:Whenever Kolaghan Aspirant becomes blocked by a creature, Kolaghan Aspirant deals 1 damage to that creature.

View File

@@ -5,7 +5,7 @@ K:UpkeepCost:1 W
K:ETBReplacement:Other:ChooseBlackOrRed K:ETBReplacement:Other:ChooseBlackOrRed
SVar:ChooseBlackOrRed:DB$ ChooseColor | Defined$ You | Choices$ black,red | AILogic$ MostProminentHumanCreatures | SpellDescription$ As CARDNAME enters the battlefield, choose black or red. SVar:ChooseBlackOrRed:DB$ ChooseColor | Defined$ You | Choices$ black,red | AILogic$ MostProminentHumanCreatures | SpellDescription$ As CARDNAME enters the battlefield, choose black or red.
T:Mode$ DamageDone | ValidSource$ Creature.ChosenColor | ValidTarget$ Creature.White+YouCtrl,You | TriggerZones$ Battlefield | Execute$ MangarasRetribution | TriggerDescription$ Whenever a creature of the chosen color deals damage to you or a white creature you control, CARDNAME deals that much damage to that creature. T:Mode$ DamageDone | ValidSource$ Creature.ChosenColor | ValidTarget$ Creature.White+YouCtrl,You | TriggerZones$ Battlefield | Execute$ MangarasRetribution | TriggerDescription$ Whenever a creature of the chosen color deals damage to you or a white creature you control, CARDNAME deals that much damage to that creature.
SVar:MangarasRetribution:DB$ DealDamage | Defined$ TriggeredSource | NumDmg$ MangaraX | References$ MangaraX SVar:MangarasRetribution:DB$ DealDamage | Defined$ TriggeredSourceLKICopy | NumDmg$ MangaraX | References$ MangaraX
SVar:MangaraX:TriggerCount$DamageAmount SVar:MangaraX:TriggerCount$DamageAmount
SVar:RemRandomDeck:True SVar:RemRandomDeck:True
SVar:Picture:http://www.wizards.com/global/images/magic/general/mangaras_equity.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/mangaras_equity.jpg

View File

@@ -3,8 +3,8 @@ ManaCost:2 R W
Types:Enchantment Types:Enchantment
T:Mode$ Attacks | ValidCard$ Creature | TriggerZones$ Battlefield | Execute$ TrigDamage | TriggerDescription$ Whenever a creature attacks or blocks, CARDNAME deals 2 damage to it. T:Mode$ Attacks | ValidCard$ Creature | TriggerZones$ Battlefield | Execute$ TrigDamage | TriggerDescription$ Whenever a creature attacks or blocks, CARDNAME deals 2 damage to it.
T:Mode$ Blocks | ValidCard$ Creature | TriggerZones$ Battlefield | Execute$ TrigDamage2 | Secondary$ True | TriggerDescription$ Whenever a creature attacks or blocks, CARDNAME deals 2 damage to it. T:Mode$ Blocks | ValidCard$ Creature | TriggerZones$ Battlefield | Execute$ TrigDamage2 | Secondary$ True | TriggerDescription$ Whenever a creature attacks or blocks, CARDNAME deals 2 damage to it.
SVar:TrigDamage:DB$DealDamage | Defined$ TriggeredAttacker | NumDmg$ 2 SVar:TrigDamage:DB$DealDamage | Defined$ TriggeredAttackerLKICopy | NumDmg$ 2
SVar:TrigDamage2:DB$DealDamage | Defined$ TriggeredBlocker | NumDmg$ 2 SVar:TrigDamage2:DB$DealDamage | Defined$ TriggeredBlockerLKICopy | NumDmg$ 2
SVar:RemRandomDeck:True SVar:RemRandomDeck:True
SVar:Picture:http://www.wizards.com/global/images/magic/general/powerstone_minefield.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/powerstone_minefield.jpg
Oracle:Whenever a creature attacks or blocks, Powerstone Minefield deals 2 damage to it. Oracle:Whenever a creature attacks or blocks, Powerstone Minefield deals 2 damage to it.

View File

@@ -3,7 +3,7 @@ ManaCost:2 G
Types:Creature Elf Shaman Types:Creature Elf Shaman
PT:2/2 PT:2/2
T:Mode$ ChangesZone | ValidCard$ Creature.Other+YouCtrl | Origin$ Any | Destination$ Battlefield | Execute$ TrigPump | TriggerZones$ Battlefield | TriggerDescription$ Whenever another creature enters the battlefield under your control, that creature gets +3/+3 until end of turn. T:Mode$ ChangesZone | ValidCard$ Creature.Other+YouCtrl | Origin$ Any | Destination$ Battlefield | Execute$ TrigPump | TriggerZones$ Battlefield | TriggerDescription$ Whenever another creature enters the battlefield under your control, that creature gets +3/+3 until end of turn.
SVar:TrigPump:DB$ Pump | Defined$ TriggeredCard | NumAtt$ +3 | NumDef$ +3 SVar:TrigPump:DB$ Pump | Defined$ TriggeredCardLKICopy | NumAtt$ +3 | NumDef$ +3
SVar:PlayMain1:ALWAYS SVar:PlayMain1:ALWAYS
SVar:Picture:http://www.wizards.com/global/images/magic/general/primal_forcemage.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/primal_forcemage.jpg
Oracle:Whenever another creature enters the battlefield under your control, that creature gets +3/+3 until end of turn. Oracle:Whenever another creature enters the battlefield under your control, that creature gets +3/+3 until end of turn.

View File

@@ -2,6 +2,6 @@ Name:Raking Canopy
ManaCost:1 G G ManaCost:1 G G
Types:Enchantment Types:Enchantment
T:Mode$ Attacks | ValidCard$ Creature.withFlying | Attacked$ You | TriggerZones$ Battlefield | Execute$ TrigDamage | TriggerDescription$ Whenever a creature with flying attacks you, CARDNAME deals 4 damage to it. T:Mode$ Attacks | ValidCard$ Creature.withFlying | Attacked$ You | TriggerZones$ Battlefield | Execute$ TrigDamage | TriggerDescription$ Whenever a creature with flying attacks you, CARDNAME deals 4 damage to it.
SVar:TrigDamage:DB$ DealDamage | Defined$ TriggeredAttacker | NumDmg$ 4 SVar:TrigDamage:DB$ DealDamage | Defined$ TriggeredAttackerLKICopy | NumDmg$ 4
SVar:Picture:http://www.wizards.com/global/images/magic/general/raking_canopy.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/raking_canopy.jpg
Oracle:Whenever a creature with flying attacks you, Raking Canopy deals 4 damage to it. Oracle:Whenever a creature with flying attacks you, Raking Canopy deals 4 damage to it.

View File

@@ -3,6 +3,6 @@ ManaCost:R
Types:Creature Human Warrior Types:Creature Human Warrior
PT:1/1 PT:1/1
T:Mode$ AttackerBlockedByCreature | ValidCard$ Card.Self | ValidBlocker$ Creature | TriggerZones$ Battlefield | Execute$ RogueDamage | TriggerDescription$ Whenever CARDNAME becomes blocked by a creature, CARDNAME deals 1 damage to that creature. T:Mode$ AttackerBlockedByCreature | ValidCard$ Card.Self | ValidBlocker$ Creature | TriggerZones$ Battlefield | Execute$ RogueDamage | TriggerDescription$ Whenever CARDNAME becomes blocked by a creature, CARDNAME deals 1 damage to that creature.
SVar:RogueDamage:DB$ DealDamage | Defined$ TriggeredBlocker | NumDmg$ 1 SVar:RogueDamage:DB$ DealDamage | Defined$ TriggeredBlockerLKICopy | NumDmg$ 1
SVar:Picture:http://www.wizards.com/global/images/magic/general/somberwald_vigilante.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/somberwald_vigilante.jpg
Oracle:Whenever Somberwald Vigilante becomes blocked by a creature, Somberwald Vigilante deals 1 damage to that creature. Oracle:Whenever Somberwald Vigilante becomes blocked by a creature, Somberwald Vigilante deals 1 damage to that creature.

View File

@@ -4,7 +4,7 @@ Types:Creature Beast
PT:4/5 PT:4/5
T:Mode$ DamageDone | ValidSource$ Creature | ValidTarget$ Card.Self | Execute$ TrigDealDamage1 | TriggerDescription$ Whenever a creature deals damage to CARDNAME, CARDNAME deals that much damage to that creature. T:Mode$ DamageDone | ValidSource$ Creature | ValidTarget$ Card.Self | Execute$ TrigDealDamage1 | TriggerDescription$ Whenever a creature deals damage to CARDNAME, CARDNAME deals that much damage to that creature.
T:Mode$ DamageDone | ValidSource$ Instant,Sorcery | ValidTarget$ Card.Self | Execute$ TrigDealDamage2 | TriggerDescription$ Whenever a spell deals damage to CARDNAME, CARDNAME deals that much damage to that spell's controller. T:Mode$ DamageDone | ValidSource$ Instant,Sorcery | ValidTarget$ Card.Self | Execute$ TrigDealDamage2 | TriggerDescription$ Whenever a spell deals damage to CARDNAME, CARDNAME deals that much damage to that spell's controller.
SVar:TrigDealDamage1:DB$ DealDamage | Defined$ TriggeredSource | NumDmg$ X | References$ X SVar:TrigDealDamage1:DB$ DealDamage | Defined$ TriggeredSourceLKICopy | NumDmg$ X | References$ X
SVar:TrigDealDamage2:DB$ DealDamage | Defined$ TriggeredSourceController | NumDmg$ X | References$ X SVar:TrigDealDamage2:DB$ DealDamage | Defined$ TriggeredSourceController | NumDmg$ X | References$ X
SVar:X:TriggerCount$DamageAmount SVar:X:TriggerCount$DamageAmount
SVar:Picture:http://www.wizards.com/global/images/magic/general/tephraderm.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/tephraderm.jpg