Attack fixes (#3241)

This commit is contained in:
tool4ever
2023-06-11 15:21:33 +02:00
committed by GitHub
parent 781eb35ee3
commit 4bc8c05a5e
15 changed files with 45 additions and 119 deletions

View File

@@ -135,16 +135,20 @@ public class AiAttackController {
return !c.isTapped() && !c.isCreature() && !c.isPlaneswalker(); return !c.isTapped() && !c.isCreature() && !c.isPlaneswalker();
} }
}; };
CardCollection tappedDefenders = new CardCollection();
for (Card c : CardLists.filter(defender.getCardsIn(ZoneType.Battlefield), canAnimate)) { for (Card c : CardLists.filter(defender.getCardsIn(ZoneType.Battlefield), canAnimate)) {
/* TODO: is the commented out code still necessary for anything? for (SpellAbility sa : Iterables.filter(c.getSpellAbilities(), SpellAbilityPredicates.isApi(ApiType.Animate))) {
if (c.isToken() && c.getCopiedPermanent() == null && !c.canTransform(null)) { if (sa.usesTargeting() || !sa.getParamOrDefault("Defined", "Self").equals("Self")) {
continue;
}
if (sa.hasParam("Crew") && !ComputerUtilCost.checkTapTypeCost(defender, sa.getPayCosts(), c, sa, tappedDefenders)) {
continue;
} else if (!ComputerUtilCost.canPayCost(sa, defender, false) || !sa.getRestrictions().checkOtherRestrictions(c, sa, defender)) {
continue; continue;
} }
*/
for (SpellAbility sa : Iterables.filter(c.getSpellAbilities(), SpellAbilityPredicates.isApi(ApiType.Animate))) {
if (ComputerUtilCost.canPayCost(sa, defender, false)
&& sa.getRestrictions().checkOtherRestrictions(c, sa, defender)) {
Card animatedCopy = AnimateAi.becomeAnimated(c, sa); Card animatedCopy = AnimateAi.becomeAnimated(c, sa);
if (animatedCopy.isCreature()) {
int saCMC = sa.getPayCosts() != null && sa.getPayCosts().hasManaCost() ? int saCMC = sa.getPayCosts() != null && sa.getPayCosts().hasManaCost() ?
sa.getPayCosts().getTotalMana().getCMC() : 0; // FIXME: imprecise, only works 100% for colorless mana sa.getPayCosts().getTotalMana().getCMC() : 0; // FIXME: imprecise, only works 100% for colorless mana
if (totalMana - manaReserved >= saCMC) { if (totalMana - manaReserved >= saCMC) {
@@ -153,6 +157,8 @@ public class AiAttackController {
} }
} }
} }
defenders.removeAll(tappedDefenders);
// Transform (e.g. Incubator tokens) // Transform (e.g. Incubator tokens)
for (SpellAbility sa : Iterables.filter(c.getSpellAbilities(), SpellAbilityPredicates.isApi(ApiType.SetState))) { for (SpellAbility sa : Iterables.filter(c.getSpellAbilities(), SpellAbilityPredicates.isApi(ApiType.SetState))) {
Card transformedCopy = ComputerUtilCombat.canTransform(c); Card transformedCopy = ComputerUtilCombat.canTransform(c);

View File

@@ -1109,7 +1109,9 @@ public class AiBlockController {
} }
// TODO could be made more accurate if this would be inside each blocker choosing loop instead // TODO could be made more accurate if this would be inside each blocker choosing loop instead
lifeInDanger |= removeUnpayableBlocks(combat) && ComputerUtilCombat.lifeInDanger(ai, combat); if (removeUnpayableBlocks(combat) || lifeInDanger) {
lifeInDanger = ComputerUtilCombat.lifeInDanger(ai, combat);
}
// == 2. If the AI life would still be in danger make a safer approach == // == 2. If the AI life would still be in danger make a safer approach ==
if (lifeInDanger) { if (lifeInDanger) {

View File

@@ -694,10 +694,8 @@ public class ComputerUtil {
public static CardCollection chooseTapType(final Player ai, final String type, final Card activate, final boolean tap, final int amount, final CardCollectionView exclude, SpellAbility sa) { public static CardCollection chooseTapType(final Player ai, final String type, final Card activate, final boolean tap, final int amount, final CardCollectionView exclude, SpellAbility sa) {
CardCollection all = new CardCollection(ai.getCardsIn(ZoneType.Battlefield)); CardCollection all = new CardCollection(ai.getCardsIn(ZoneType.Battlefield));
all.removeAll(exclude); all.removeAll(exclude);
CardCollection typeList = CardCollection typeList = CardLists.getValidCards(all, type.split(";"), activate.getController(), activate, sa);
CardLists.getValidCards(all, type.split(";"), activate.getController(), activate, sa);
// is this needed?
typeList = CardLists.filter(typeList, Presets.UNTAPPED); typeList = CardLists.filter(typeList, Presets.UNTAPPED);
if (tap) { if (tap) {
@@ -733,7 +731,6 @@ public class ComputerUtil {
typeList = CardLists.getNotKeyword(typeList, "CARDNAME can't crew Vehicles."); typeList = CardLists.getNotKeyword(typeList, "CARDNAME can't crew Vehicles.");
} }
// is this needed?
typeList = CardLists.filter(typeList, Presets.UNTAPPED); typeList = CardLists.filter(typeList, Presets.UNTAPPED);
if (tap) { if (tap) {
@@ -772,7 +769,6 @@ public class ComputerUtil {
CardCollection typeList = CardCollection typeList =
CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, sa); CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, sa);
// is this needed?
typeList = CardLists.filter(typeList, Presets.TAPPED); typeList = CardLists.filter(typeList, Presets.TAPPED);
if (untap) { if (untap) {

View File

@@ -415,7 +415,7 @@ public class ComputerUtilCost {
* the source * the source
* @return true, if successful * @return true, if successful
*/ */
public static boolean checkTapTypeCost(final Player ai, final Cost cost, final Card source, final SpellAbility sa) { public static boolean checkTapTypeCost(final Player ai, final Cost cost, final Card source, final SpellAbility sa, final CardCollection alreadyTapped) {
if (cost == null) { if (cost == null) {
return true; return true;
} }
@@ -442,8 +442,13 @@ public class ComputerUtilCost {
return ComputerUtilCard.evaluateCreature(c) >= vehicleValue; return ComputerUtilCard.evaluateCreature(c) >= vehicleValue;
} }
}); // exclude creatures >= vehicle }); // exclude creatures >= vehicle
return ComputerUtil.chooseTapTypeAccumulatePower(ai, type, sa, true, exclude.addAll(alreadyTapped);
Integer.parseInt(totalP), exclude) != null; CardCollection tappedCrew = ComputerUtil.chooseTapTypeAccumulatePower(ai, type, sa, true, Integer.parseInt(totalP), exclude);
if (tappedCrew != null) {
alreadyTapped.addAll(tappedCrew);
return true;
}
return false;
} }
// check if we have a valid card to tap (e.g. Jaspera Sentinel) // check if we have a valid card to tap (e.g. Jaspera Sentinel)
@@ -480,36 +485,6 @@ public class ComputerUtilCost {
return true; return true;
} }
/**
* <p>
* shouldPayCost.
* </p>
*
* @param hostCard
* a {@link forge.game.card.Card} object.
* @param cost
* @return a boolean.
*/
@Deprecated
public static boolean shouldPayCost(final Player ai, final Card hostCard, final Cost cost) {
for (final CostPart part : cost.getCostParts()) {
if (part instanceof CostPayLife) {
if (!ai.cantLoseForZeroOrLessLife()) {
continue;
}
final int remainingLife = ai.getLife();
final int lifeCost = part.convertAmount();
if ((remainingLife - lifeCost) < 10) {
return false; //Don't pay life if it would put AI under 10 life
} else if ((remainingLife / lifeCost) < 4) {
return false; //Don't pay life if it is more than 25% of current life
}
}
}
return true;
} // shouldPayCost()
/** /**
* <p> * <p>
* canPayCost. * canPayCost.
@@ -580,15 +555,6 @@ public class ComputerUtilCost {
} }
} }
// KLD vehicle
if (sa.hasParam("Crew")) { // put under checkTapTypeCost?
for (final CostPart part : sa.getPayCosts().getCostParts()) {
if (part instanceof CostTapType && part.getType().contains("+withTotalPowerGE")) {
return new AiCostDecision(player, sa, false).visit((CostTapType)part) != null;
}
}
}
// Ward - will be accounted for when rechecking a targeted ability // Ward - will be accounted for when rechecking a targeted ability
if (!sa.isTrigger() && sa.usesTargeting() && (!sa.isSpell() || !cannotBeCountered)) { if (!sa.isTrigger() && sa.usesTargeting() && (!sa.isSpell() || !cannotBeCountered)) {
for (Card tgt : sa.getTargets().getTargetCards()) { for (Card tgt : sa.getTargets().getTargetCards()) {

View File

@@ -312,7 +312,7 @@ public class ComputerUtilMana {
continue; continue;
} }
if (!ComputerUtilCost.checkTapTypeCost(ai, ma.getPayCosts(), ma.getHostCard(), sa)) { if (!ComputerUtilCost.checkTapTypeCost(ai, ma.getPayCosts(), ma.getHostCard(), sa, new CardCollection())) {
continue; continue;
} }

View File

@@ -130,7 +130,7 @@ public class AnimateAi extends SpellAbilityAi {
return true; // interrupt sacrifice return true; // interrupt sacrifice
} }
} }
if (!ComputerUtilCost.checkTapTypeCost(aiPlayer, sa.getPayCosts(), source, sa)) { if (!ComputerUtilCost.checkTapTypeCost(aiPlayer, sa.getPayCosts(), source, sa, new CardCollection())) {
return false; // prevent crewing with equal or better creatures return false; // prevent crewing with equal or better creatures
} }
@@ -379,7 +379,7 @@ public class AnimateAi extends SpellAbilityAi {
return copy; return copy;
} }
public static void becomeAnimated(final Card card, final boolean hasOriginalCardSickness, final SpellAbility sa) { private static void becomeAnimated(final Card card, final boolean hasOriginalCardSickness, final SpellAbility sa) {
// duplicating AnimateEffect.resolve // duplicating AnimateEffect.resolve
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
final Game game = sa.getActivatingPlayer().getGame(); final Game game = sa.getActivatingPlayer().getGame();

View File

@@ -78,15 +78,7 @@ public class SacrificeAi extends SpellAbilityAi {
String num = sa.getParamOrDefault("Amount" , "1"); String num = sa.getParamOrDefault("Amount" , "1");
final int amount = AbilityUtils.calculateAmount(source, num, sa); final int amount = AbilityUtils.calculateAmount(source, num, sa);
List<Card> list = null; List<Card> list = CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid, sa.getActivatingPlayer(), source, sa);
try {
list = CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid, sa.getActivatingPlayer(), source, sa);
} catch (NullPointerException e) {
return false;
} finally {
if (list == null)
return false;
}//prevent NPE on MoJhoSto
for (Card c : list) { for (Card c : list) {
if (c.hasSVar("SacMe") && Integer.parseInt(c.getSVar("SacMe")) > 3) { if (c.hasSVar("SacMe") && Integer.parseInt(c.getSVar("SacMe")) > 3) {
@@ -140,30 +132,13 @@ public class SacrificeAi extends SpellAbilityAi {
amount = Math.min(ComputerUtilCost.getMaxXValue(sa, ai, sa.isTrigger()), amount); amount = Math.min(ComputerUtilCost.getMaxXValue(sa, ai, sa.isTrigger()), amount);
} }
List<Card> humanList = null; List<Card> humanList = CardLists.getValidCards(ai.getStrongestOpponent().getCardsIn(ZoneType.Battlefield), valid, sa.getActivatingPlayer(), source, sa);
try {
humanList = CardLists.getValidCards(ai.getStrongestOpponent().getCardsIn(ZoneType.Battlefield), valid, sa.getActivatingPlayer(), source, sa);
} catch (NullPointerException e) {
return false;
} finally {
if (humanList == null)
return false;
}//prevent NPE on MoJhoSto
// Since all of the cards have AI:RemoveDeck:All, I enabled 1 for 1 // Since all of the cards have AI:RemoveDeck:All, I enabled 1 for 1
// (or X for X) trades for special decks // (or X for X) trades for special decks
return humanList.size() >= amount; return humanList.size() >= amount;
} else if (defined.equals("You")) { } else if (defined.equals("You")) {
List<Card> computerList = null; List<Card> computerList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), valid, sa.getActivatingPlayer(), source, sa);
try {
computerList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), valid, sa.getActivatingPlayer(), source, sa);
} catch (NullPointerException e) {
return false;
} finally {
if (computerList == null)
return false;
}//prevent NPE on MoJhoSto
for (Card c : computerList) { for (Card c : computerList) {
if (c.hasSVar("SacMe") || ComputerUtilCard.evaluateCreature(c) <= 135) { if (c.hasSVar("SacMe") || ComputerUtilCard.evaluateCreature(c) <= 135) {
return true; return true;

View File

@@ -2180,34 +2180,20 @@ public class AbilityUtils {
return doXMath(Integer.parseInt(sq[isMyMain ? 1 : 2]), expr, c, ctb); return doXMath(Integer.parseInt(sq[isMyMain ? 1 : 2]), expr, c, ctb);
} }
// Count$AttachedTo <DefinedCards related to spellability> <restriction> // Count$AttachedTo <restriction>
if (sq[0].startsWith("AttachedTo")) { if (sq[0].startsWith("AttachedTo")) {
final String[] k = l[0].split(" "); final String[] k = l[0].split(" ");
int sum = 0; int sum = CardLists.getValidCardCount(c.getAttachedCards(), k[1], player, c, ctb);
for (Card card : getDefinedCards(c, k[1], ctb)) {
// Hateful Eidolon: the script uses LKI so that the attached cards have to be defined
// This card needs the spellability ("Auras You control", you refers to the activating player)
// CardFactoryUtils.xCount doesn't have the sa parameter, SVar:X:TriggeredCard$Valid <restriction> cannot handle this
sum += CardLists.getValidCardCount(card.getAttachedCards(), k[2], player, c, ctb);
}
return doXMath(sum, expr, c, ctb); return doXMath(sum, expr, c, ctb);
} }
// Count$CardManaCost // Count$CardManaCost
if (sq[0].contains("CardManaCost")) { if (sq[0].contains("CardManaCost")) {
Card ce; int cmc = c.getCMC();
if (sq[0].contains("Remembered")) {
ce = (Card) c.getFirstRemembered();
}
else {
ce = c;
}
int cmc = ce == null ? 0 : ce.getCMC(); if (sq[0].contains("LKI") && ctb instanceof SpellAbility && !c.isInZone(ZoneType.Stack) && c.getManaCost() != null) {
if (sq[0].contains("LKI") && ctb instanceof SpellAbility && ce != null && !ce.isInZone(ZoneType.Stack) && ce.getManaCost() != null) {
if (((SpellAbility) ctb).getXManaCostPaid() != null) { if (((SpellAbility) ctb).getXManaCostPaid() != null) {
cmc += ((SpellAbility) ctb).getXManaCostPaid() * ce.getManaCost().countX(); cmc += ((SpellAbility) ctb).getXManaCostPaid() * c.getManaCost().countX();
} }
} }

View File

@@ -33,7 +33,6 @@ public class ChangeTargetsEffect extends SpellAbilityEffect {
@Override @Override
public void resolve(SpellAbility sa) { public void resolve(SpellAbility sa) {
final List<SpellAbility> sas = getTargetSpells(sa); final List<SpellAbility> sas = getTargetSpells(sa);
final boolean remember = sa.hasParam("RememberTargetedCard");
final Player activator = sa.getActivatingPlayer(); final Player activator = sa.getActivatingPlayer();
final Player chooser = sa.hasParam("Chooser") ? getDefinedPlayersOrTargeted(sa, "Chooser").get(0) : sa.getActivatingPlayer(); final Player chooser = sa.hasParam("Chooser") ? getDefinedPlayersOrTargeted(sa, "Chooser").get(0) : sa.getActivatingPlayer();
@@ -140,9 +139,6 @@ public class ChangeTargetsEffect extends SpellAbilityEffect {
changingTgtSI = changingTgtSI.getSubInstance(); changingTgtSI = changingTgtSI.getSubInstance();
} }
} }
if (remember) {
sa.getHostCard().addRemembered(tgtSA.getHostCard());
}
} }
} }
} }

View File

@@ -5,7 +5,7 @@ PT:6/6
K:Convoke K:Convoke
K:Trample K:Trample
K:Ward:2 K:Ward:2
K:etbCounter:P1P1:X K:etbCounter:P1P1:X:no condition:CARDNAME enters the battlefield with two +1/+1 counters on it for each creature that convoked it.
SVar:X:Convoked$Amount/Twice SVar:X:Convoked$Amount/Twice
DeckHas:Ability$Counters DeckHas:Ability$Counters
Oracle:Convoke (Your creatures can help cast this spell. Each creature you tap while casting this spell pays for {1} or one mana of that creature's color.)\nTrample, ward {2}\nAncient Imperiosaur enters the battlefield with two +1/+1 counters on it for each creature that convoked it. Oracle:Convoke (Your creatures can help cast this spell. Each creature you tap while casting this spell pays for {1} or one mana of that creature's color.)\nTrample, ward {2}\nAncient Imperiosaur enters the battlefield with two +1/+1 counters on it for each creature that convoked it.

View File

@@ -15,7 +15,7 @@ SVar:DBScry:DB$ Scry | ScryNum$ 2
A:AB$ Dig | Cost$ SubCounter<3/LOYALTY> | Planeswalker$ True | DigNum$ 1 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | Reveal$ True | SubAbility$ DBToken | SpellDescription$ Exile the top card of your library. A:AB$ Dig | Cost$ SubCounter<3/LOYALTY> | Planeswalker$ True | DigNum$ 1 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | Reveal$ True | SubAbility$ DBToken | SpellDescription$ Exile the top card of your library.
SVar:DBToken:DB$ Token | TokenAmount$ Z | TokenScript$ u_1_1_faerie_dragon_flying | SubAbility$ DBCleanup | SpellDescription$ Create a number of 1/1 blue Faerie Dragon creature tokens with flying equal to that card's mana value. SVar:DBToken:DB$ Token | TokenAmount$ Z | TokenScript$ u_1_1_faerie_dragon_flying | SubAbility$ DBCleanup | SpellDescription$ Create a number of 1/1 blue Faerie Dragon creature tokens with flying equal to that card's mana value.
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:Z:Count$RememberedCardManaCost SVar:Z:Remembered$CardManaCost
Text:CARDNAME can be your commander. Text:CARDNAME can be your commander.
DeckHas:Ability$Token & Type$Faerie|Dragon DeckHas:Ability$Token & Type$Faerie|Dragon
DeckHints:Type$Instant|Sorcery DeckHints:Type$Instant|Sorcery

View File

@@ -5,6 +5,6 @@ PT:1/2
K:Lifelink K:Lifelink
T:Mode$ ChangesZone | ValidCard$ Creature.enchanted | Origin$ Battlefield | Destination$ Graveyard | TriggerZones$ Battlefield | Execute$ TrigDraw | TriggerDescription$ Whenever an enchanted creature dies, draw a card for each Aura you controlled that was attached to it. T:Mode$ ChangesZone | ValidCard$ Creature.enchanted | Origin$ Battlefield | Destination$ Graveyard | TriggerZones$ Battlefield | Execute$ TrigDraw | TriggerDescription$ Whenever an enchanted creature dies, draw a card for each Aura you controlled that was attached to it.
SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ X SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ X
SVar:X:Count$AttachedTo TriggeredCardLKICopy Aura.YouCtrl SVar:X:TriggeredCard$AttachedTo Aura.YouCtrl
SVar:EnchantMe:Multiple SVar:EnchantMe:Multiple
Oracle:Lifelink\nWhenever an enchanted creature dies, draw a card for each Aura you controlled that was attached to it. Oracle:Lifelink\nWhenever an enchanted creature dies, draw a card for each Aura you controlled that was attached to it.

View File

@@ -1,9 +1,8 @@
Name:Imp's Mischief Name:Imp's Mischief
ManaCost:1 B ManaCost:1 B
Types:Instant Types:Instant
A:SP$ ChangeTargets | TargetType$ Spell.singleTarget | ValidTgts$ Card | TgtPrompt$ Select target spell with a single target | RememberTargetedCard$ True | SubAbility$ DBLoseLife | SpellDescription$ Change the target of target spell with a single target. You lose life equal to that spell's mana value. A:SP$ ChangeTargets | TargetType$ Spell.singleTarget | ValidTgts$ Card | TgtPrompt$ Select target spell with a single target | SubAbility$ DBLoseLife | SpellDescription$ Change the target of target spell with a single target. You lose life equal to that spell's mana value.
SVar:DBLoseLife:DB$ LoseLife | LifeAmount$ X | SubAbility$ DBCleanup SVar:DBLoseLife:DB$ LoseLife | LifeAmount$ X
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:X:Targeted$CardManaCost
SVar:X:Remembered$CardManaCost
AI:RemoveDeck:All AI:RemoveDeck:All
Oracle:Change the target of target spell with a single target. You lose life equal to that spell's mana value. Oracle:Change the target of target spell with a single target. You lose life equal to that spell's mana value.

View File

@@ -5,7 +5,7 @@ PT:*/*
K:ETBReplacement:Copy:ChooseSpell K:ETBReplacement:Copy:ChooseSpell
SVar:ChooseSpell:DB$ ChangeZone | ChangeType$ Instant.YouOwn,Sorcery.YouOwn | ChangeNum$ 1 | Hidden$ True | Origin$ Graveyard | Destination$ Exile | RememberChanged$ True | Mandatory$ True | SpellDescription$ As CARDNAME enters the battlefield, exile an instant or sorcery card from your graveyard. SVar:ChooseSpell:DB$ ChangeZone | ChangeType$ Instant.YouOwn,Sorcery.YouOwn | ChangeNum$ 1 | Hidden$ True | Origin$ Graveyard | Destination$ Exile | RememberChanged$ True | Mandatory$ True | SpellDescription$ As CARDNAME enters the battlefield, exile an instant or sorcery card from your graveyard.
S:Mode$ Continuous | EffectZone$ All | CharacteristicDefining$ True | SetPower$ X | SetToughness$ X | Description$ CARDNAME's power and toughness are each equal to the exiled card's mana value. S:Mode$ Continuous | EffectZone$ All | CharacteristicDefining$ True | SetPower$ X | SetToughness$ X | Description$ CARDNAME's power and toughness are each equal to the exiled card's mana value.
SVar:X:Count$RememberedCardManaCost SVar:X:Remembered$CardManaCost
T:Mode$ DamageDealtOnce | CombatDamage$ True | ValidSource$ Card.Self | Execute$ TrigSacLore | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage, you may sacrifice it. If you do, you may cast the exiled card without paying its mana cost. T:Mode$ DamageDealtOnce | CombatDamage$ True | ValidSource$ Card.Self | Execute$ TrigSacLore | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage, you may sacrifice it. If you do, you may cast the exiled card without paying its mana cost.
SVar:TrigSacLore:AB$ Play | Cost$ Sac<1/CARDNAME> | Defined$ Remembered | Amount$ All | Controller$ You | WithoutManaCost$ True | ValidSA$ Spell | Optional$ True | ForgetRemembered$ True SVar:TrigSacLore:AB$ Play | Cost$ Sac<1/CARDNAME> | Defined$ Remembered | Amount$ All | Controller$ You | WithoutManaCost$ True | ValidSA$ Spell | Optional$ True | ForgetRemembered$ True
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup

View File

@@ -8,6 +8,6 @@ SVar:SparkDamage:DB$ DealDamage | Defined$ ParentTarget | NumDmg$ X | SpellDescr
SVar:SparkPlay:DB$ Effect | RememberObjects$ RememberedCard | StaticAbilities$ Play | ExileOnMoved$ Exile | SpellDescription$ You may play exiled card until end of turn. SVar:SparkPlay:DB$ Effect | RememberObjects$ RememberedCard | StaticAbilities$ Play | ExileOnMoved$ Exile | SpellDescription$ You may play exiled card until end of turn.
SVar:Play:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may play remembered card. SVar:Play:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may play remembered card.
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Count$RememberedCardManaCost SVar:X:Remembered$CardManaCost
AI:RemoveDeck:All AI:RemoveDeck:All
Oracle:Choose target creature. Exile the top card of your library. You may have Spark of Creativity deal damage to that creature equal to the exiled card's mana value. If you don't, you may play that card until end of turn. Oracle:Choose target creature. Exile the top card of your library. You may have Spark of Creativity deal damage to that creature equal to the exiled card's mana value. If you don't, you may play that card until end of turn.