diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java
index 94c9582e2d7..cc75147856b 100644
--- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java
+++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java
@@ -970,8 +970,18 @@ public class PlayerControllerAi extends PlayerController {
@Override
public void orderAndPlaySimultaneousSa(List activePlayerSAs) {
for (final SpellAbility sa : getAi().orderPlaySa(activePlayerSAs)) {
- if (prepareSingleSa(sa.getHostCard(),sa,true)) {
+ if (sa.isTrigger() && prepareSingleSa(sa.getHostCard(), sa, true)) {
ComputerUtil.playStack(sa, player, game);
+ } else if (sa.isCopied()) {
+ player.getGame().getStackZone().add(sa.getHostCard());
+ // TODO check if static abilities needs to be run for things affecting the copy?
+ if (sa.isMayChooseNewTargets() && !sa.setupTargets()) {
+ // if targets can't be done, remove copy from existence
+ sa.getHostCard().ceaseToExist();
+ continue;
+ }
+ // need finally add the new spell to the stack
+ player.getGame().getStack().add(sa);
}
}
}
diff --git a/forge-ai/src/main/java/forge/ai/ability/DelayedTriggerAi.java b/forge-ai/src/main/java/forge/ai/ability/DelayedTriggerAi.java
index c5b17785e61..bd22d902785 100644
--- a/forge-ai/src/main/java/forge/ai/ability/DelayedTriggerAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/DelayedTriggerAi.java
@@ -1,14 +1,18 @@
package forge.ai.ability;
-import forge.ai.AiController;
-import forge.ai.AiPlayDecision;
-import forge.ai.PlayerControllerAi;
-import forge.ai.SpellAbilityAi;
-import forge.ai.SpellApiToAi;
+import com.google.common.base.Predicate;
+import forge.ai.*;
+import forge.card.mana.ManaCost;
import forge.game.ability.AbilityFactory;
+import forge.game.ability.ApiType;
+import forge.game.card.Card;
+import forge.game.card.CardLists;
+import forge.game.cost.Cost;
+import forge.game.keyword.Keyword;
import forge.game.player.Player;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
+import forge.game.zone.ZoneType;
public class DelayedTriggerAi extends SpellAbilityAi {
@@ -53,6 +57,92 @@ public class DelayedTriggerAi extends SpellAbilityAi {
@Override
protected boolean canPlayAI(Player ai, SpellAbility sa) {
+ // Card-specific logic
+ String logic = sa.getParamOrDefault("AILogic", "");
+ if (logic.equals("SpellCopy")) {
+ // fetch Instant or Sorcery and AI has reason to play this turn
+ // does not try to get itself
+ final ManaCost costSa = sa.getPayCosts().getTotalMana();
+ final int count = CardLists.count(ai.getCardsIn(ZoneType.Hand), new Predicate() {
+ @Override
+ public boolean apply(final Card c) {
+ if (!(c.isInstant() || c.isSorcery()) || c.equals(sa.getHostCard())) {
+ return false;
+ }
+ for (SpellAbility ab : c.getSpellAbilities()) {
+ if (ComputerUtilAbility.getAbilitySourceName(sa).equals(ComputerUtilAbility.getAbilitySourceName(ab))
+ || ab.hasParam("AINoRecursiveCheck")) {
+ // prevent infinitely recursing mana ritual and other abilities with reentry
+ continue;
+ } else if ("SpellCopy".equals(ab.getParam("AILogic")) && ab.getApi() == ApiType.DelayedTrigger) {
+ // don't copy another copy spell, too complex for the AI
+ continue;
+ }
+ if (!ab.canPlay()) {
+ continue;
+ }
+ AiPlayDecision decision = ((PlayerControllerAi)ai.getController()).getAi().canPlaySa(ab);
+ // see if we can pay both for this spell and for the Effect spell we're considering
+ if (decision == AiPlayDecision.WillPlay || decision == AiPlayDecision.WaitForMain2) {
+ ManaCost costAb = ab.getPayCosts().getTotalMana();
+ ManaCost total = ManaCost.combine(costSa, costAb);
+ SpellAbility combinedAb = ab.copyWithDefinedCost(new Cost(total, false));
+ // can we pay both costs?
+ if (ComputerUtilMana.canPayManaCost(combinedAb, ai, 0)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ });
+
+ if(count == 0) {
+ return false;
+ }
+ return true;
+ } else if (logic.equals("NarsetRebound")) {
+ // should be done in Main2, but it might broke for other cards
+ //if (phase.getPhase().isBefore(PhaseType.MAIN2)) {
+ // return false;
+ //}
+
+ // fetch Instant or Sorcery without Rebound and AI has reason to play this turn
+ // only need count, not the list
+ final int count = CardLists.count(ai.getCardsIn(ZoneType.Hand), new Predicate() {
+ @Override
+ public boolean apply(final Card c) {
+ if (!(c.isInstant() || c.isSorcery()) || c.hasKeyword(Keyword.REBOUND)) {
+ return false;
+ }
+ for (SpellAbility ab : c.getSpellAbilities()) {
+ if (ComputerUtilAbility.getAbilitySourceName(sa).equals(ComputerUtilAbility.getAbilitySourceName(ab))
+ || ab.hasParam("AINoRecursiveCheck")) {
+ // prevent infinitely recursing mana ritual and other abilities with reentry
+ continue;
+ }
+ if (!ab.canPlay()) {
+ continue;
+ }
+ AiPlayDecision decision = ((PlayerControllerAi) ai.getController()).getAi().canPlaySa(ab);
+ if (decision == AiPlayDecision.WillPlay || decision == AiPlayDecision.WaitForMain2) {
+ if (ComputerUtilMana.canPayManaCost(ab, ai, 0)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ });
+
+ if (count == 0) {
+ return false;
+ }
+
+ return true;
+ }
+
+ // Generic logic
SpellAbility trigsa = null;
if (sa.hasAdditionalAbility("Execute")) {
trigsa = sa.getAdditionalAbility("Execute");
diff --git a/forge-ai/src/main/java/forge/ai/ability/EffectAi.java b/forge-ai/src/main/java/forge/ai/ability/EffectAi.java
index 77a20350e69..566746434aa 100644
--- a/forge-ai/src/main/java/forge/ai/ability/EffectAi.java
+++ b/forge-ai/src/main/java/forge/ai/ability/EffectAi.java
@@ -7,14 +7,11 @@ import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import forge.ai.*;
-import forge.card.mana.ManaCost;
import forge.game.Game;
import forge.game.ability.ApiType;
import forge.game.card.*;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
-import forge.game.cost.Cost;
-import forge.game.keyword.Keyword;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
@@ -109,89 +106,6 @@ public class EffectAi extends SpellAbilityAi {
|| CardLists.getType(ai.getCardsIn(ZoneType.Battlefield), "Planeswalker").isEmpty()) {
return false;
}
- randomReturn = true;
- } else if (logic.equals("SpellCopy")) {
- // fetch Instant or Sorcery and AI has reason to play this turn
- // does not try to get itself
- final ManaCost costSa = sa.getPayCosts().getTotalMana();
- final int count = CardLists.count(ai.getCardsIn(ZoneType.Hand), new Predicate() {
- @Override
- public boolean apply(final Card c) {
- if (!(c.isInstant() || c.isSorcery()) || c.equals(sa.getHostCard())) {
- return false;
- }
- for (SpellAbility ab : c.getSpellAbilities()) {
- if (ComputerUtilAbility.getAbilitySourceName(sa).equals(ComputerUtilAbility.getAbilitySourceName(ab))
- || ab.hasParam("AINoRecursiveCheck")) {
- // prevent infinitely recursing mana ritual and other abilities with reentry
- continue;
- } else if ("SpellCopy".equals(ab.getParam("AILogic")) && ab.getApi() == ApiType.Effect) {
- // don't copy another copy spell, too complex for the AI
- continue;
- }
- if (!ab.canPlay()) {
- continue;
- }
- AiPlayDecision decision = ((PlayerControllerAi)ai.getController()).getAi().canPlaySa(ab);
- // see if we can pay both for this spell and for the Effect spell we're considering
- if (decision == AiPlayDecision.WillPlay || decision == AiPlayDecision.WaitForMain2) {
- ManaCost costAb = ab.getPayCosts().getTotalMana();
- ManaCost total = ManaCost.combine(costSa, costAb);
- SpellAbility combinedAb = ab.copyWithDefinedCost(new Cost(total, false));
- // can we pay both costs?
- if (ComputerUtilMana.canPayManaCost(combinedAb, ai, 0)) {
- return true;
- }
- }
- }
-
- return false;
- }
- });
-
- if(count == 0) {
- return false;
- }
-
- randomReturn = true;
- } else if (logic.equals("NarsetRebound")) {
- // should be done in Main2, but it might broke for other cards
- //if (phase.getPhase().isBefore(PhaseType.MAIN2)) {
- // return false;
- //}
-
- // fetch Instant or Sorcery without Rebound and AI has reason to play this turn
- // only need count, not the list
- final int count = CardLists.count(ai.getCardsIn(ZoneType.Hand), new Predicate() {
- @Override
- public boolean apply(final Card c) {
- if (!(c.isInstant() || c.isSorcery()) || c.hasKeyword(Keyword.REBOUND)) {
- return false;
- }
- for (SpellAbility ab : c.getSpellAbilities()) {
- if (ComputerUtilAbility.getAbilitySourceName(sa).equals(ComputerUtilAbility.getAbilitySourceName(ab))
- || ab.hasParam("AINoRecursiveCheck")) {
- // prevent infinitely recursing mana ritual and other abilities with reentry
- continue;
- }
- if (!ab.canPlay()) {
- continue;
- }
- AiPlayDecision decision = ((PlayerControllerAi)ai.getController()).getAi().canPlaySa(ab);
- if (decision == AiPlayDecision.WillPlay || decision == AiPlayDecision.WaitForMain2) {
- if (ComputerUtilMana.canPayManaCost(ab, ai, 0)) {
- return true;
- }
- }
- }
- return false;
- }
- });
-
- if(count == 0) {
- return false;
- }
-
randomReturn = true;
} else if (logic.equals("Always")) {
randomReturn = true;
diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java
index 16b2d97728e..6366d297ffd 100644
--- a/forge-game/src/main/java/forge/game/GameAction.java
+++ b/forge-game/src/main/java/forge/game/GameAction.java
@@ -103,7 +103,7 @@ public class GameAction {
boolean wasFacedown = c.isFaceDown();
//Rule 110.5g: A token that has left the battlefield can't move to another zone
- if (c.isToken() && zoneFrom != null && !fromBattlefield) {
+ if (c.isToken() && zoneFrom != null && !fromBattlefield && !zoneFrom.is(ZoneType.Stack)) {
return c;
}
diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java
index 9c45bc442a9..a925a35b5d4 100644
--- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java
+++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java
@@ -1660,12 +1660,8 @@ public class AbilityUtils {
// Count$Kicked..
if (sq[0].startsWith("Kicked")) {
- if (((SpellAbility)ctb).isKicked()) {
- return CardFactoryUtil.doXMath(Integer.parseInt(sq[1]), expr, c); // Kicked
- }
- else {
- return CardFactoryUtil.doXMath(Integer.parseInt(sq[2]), expr, c); // not Kicked
- }
+ boolean kicked = ((SpellAbility)ctb).isKicked() || c.getKickerMagnitude() > 0;
+ return CardFactoryUtil.doXMath(Integer.parseInt(kicked ? sq[1] : sq[2]), expr, c);
}
//Count$SearchedLibrary.
diff --git a/forge-game/src/main/java/forge/game/ability/effects/AttachEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AttachEffect.java
index cd8325cdba9..0156e9775c7 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/AttachEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/AttachEffect.java
@@ -24,14 +24,23 @@ import java.util.List;
public class AttachEffect extends SpellAbilityEffect {
@Override
public void resolve(SpellAbility sa) {
- if (sa.getHostCard().isAura() && sa.isSpell()) {
-
+ final Card host = sa.getHostCard();
+ if (host.isAura() && sa.isSpell()) {
final Player ap = sa.getActivatingPlayer();
// The Spell_Permanent (Auras) version of this AF needs to
// move the card into play before Attaching
- sa.getHostCard().setController(ap, 0);
- final Card c = ap.getGame().getAction().moveTo(ap.getZone(ZoneType.Battlefield), sa.getHostCard(), sa);
+ host.setController(ap, 0);
+
+ // 111.11. A copy of a permanent spell becomes a token as it resolves.
+ // The token has the characteristics of the spell that became that token.
+ // The token is not “created” for the purposes of any replacement effects or triggered abilities that refer to creating a token.
+ if (host.isCopiedSpell()) {
+ host.setCopiedSpell(false);
+ host.setToken(true);
+ }
+
+ final Card c = ap.getGame().getAction().moveToPlay(host, ap, sa);
sa.setHostCard(c);
}
diff --git a/forge-game/src/main/java/forge/game/ability/effects/CopySpellAbilityEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CopySpellAbilityEffect.java
index 43e13b56480..c1596d087fb 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/CopySpellAbilityEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/CopySpellAbilityEffect.java
@@ -4,7 +4,9 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
+import forge.game.Game;
import forge.game.GameEntity;
+import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
@@ -12,15 +14,16 @@ import forge.game.card.CardCollection;
import forge.game.card.CardFactory;
import forge.game.card.CardLists;
import forge.game.player.Player;
+import forge.game.replacement.ReplacementType;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
-import forge.util.Lang;
import forge.util.Localizer;
import forge.util.CardTranslation;
-import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
+
public class CopySpellAbilityEffect extends SpellAbilityEffect {
@@ -56,7 +59,8 @@ public class CopySpellAbilityEffect extends SpellAbilityEffect {
@Override
public void resolve(SpellAbility sa) {
final Card card = sa.getHostCard();
- Player controller = sa.getActivatingPlayer();
+ final Game game = card.getGame();
+ List controllers = Lists.newArrayList(sa.getActivatingPlayer());
int amount = 1;
if (sa.hasParam("Amount")) {
@@ -64,13 +68,9 @@ public class CopySpellAbilityEffect extends SpellAbilityEffect {
}
if (sa.hasParam("Controller")) {
- controller = AbilityUtils.getDefinedPlayers(card, sa.getParam("Controller"), sa).get(0);
+ controllers = AbilityUtils.getDefinedPlayers(card, sa.getParam("Controller"), sa);
}
- boolean isOptional = sa.hasParam("Optional");
- if (isOptional && !controller.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoyouWantCopyTheSpell", CardTranslation.getTranslatedName(card.getName())))) {
- return;
- }
final List tgtSpells = getTargetSpells(sa);
@@ -79,123 +79,143 @@ public class CopySpellAbilityEffect extends SpellAbilityEffect {
return;
}
- boolean mayChooseNewTargets = true;
- List copies = new ArrayList<>();
-
- if (sa.hasParam("CopyMultipleSpells")) {
- final int spellCount = Integer.parseInt(sa.getParam("CopyMultipleSpells"));
+ boolean isOptional = sa.hasParam("Optional");
- for (int multi = 0; multi < spellCount && !tgtSpells.isEmpty(); multi++) {
- String prompt = Localizer.getInstance().getMessage("lblSelectMultiSpellCopyToStack", Lang.getOrdinal(multi + 1));
- SpellAbility chosen = controller.getController().chooseSingleSpellForEffect(tgtSpells, sa, prompt,
- ImmutableMap.of());
- SpellAbility copiedSpell = CardFactory.copySpellAbilityAndPossiblyHost(card, chosen.getHostCard(), chosen, true);
- copiedSpell.getHostCard().setController(card.getController(), card.getGame().getNextTimestamp());
- copiedSpell.setActivatingPlayer(controller);
- copies.add(copiedSpell);
- tgtSpells.remove(chosen);
+ for (Player controller : controllers) {
+ if (isOptional && !controller.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoyouWantCopyTheSpell", CardTranslation.getTranslatedName(card.getName())))) {
+ continue;
}
- }
- else if (sa.hasParam("CopyForEachCanTarget")) {
+
+ List copies = Lists.newArrayList();
+
SpellAbility chosenSA = controller.getController().chooseSingleSpellForEffect(tgtSpells, sa,
Localizer.getInstance().getMessage("lblSelectASpellCopy"), ImmutableMap.of());
- chosenSA.setActivatingPlayer(controller);
- // Find subability or rootability that has targets
- SpellAbility targetedSA = chosenSA;
- while (targetedSA != null) {
- if (targetedSA.usesTargeting() && targetedSA.getTargets().getNumTargeted() != 0) {
- break;
+
+ if (sa.hasParam("CopyForEachCanTarget")) {
+ // Find subability or rootability that has targets
+ SpellAbility targetedSA = chosenSA;
+ while (targetedSA != null) {
+ if (targetedSA.usesTargeting() && targetedSA.getTargets().getNumTargeted() != 0) {
+ break;
+ }
+ targetedSA = targetedSA.getSubAbility();
}
- targetedSA = targetedSA.getSubAbility();
- }
- if (targetedSA == null) {
- return;
- }
- final List candidates = targetedSA.getTargetRestrictions().getAllCandidates(targetedSA, true);
- if (sa.hasParam("CanTargetPlayer")) {
- // Radiate
- // Remove targeted players because getAllCandidates include all the valid players
- for(Player p : targetedSA.getTargets().getTargetPlayers())
- candidates.remove(p);
-
- mayChooseNewTargets = false;
- for (GameEntity o : candidates) {
- SpellAbility copy = CardFactory.copySpellAbilityAndPossiblyHost(card, chosenSA.getHostCard(), chosenSA, true);
- resetFirstTargetOnCopy(copy, o, targetedSA);
- copies.add(copy);
+ if (targetedSA == null) {
+ continue;
}
- } else {// Precursor Golem, Ink-Treader Nephilim
- final String type = sa.getParam("CopyForEachCanTarget");
- CardCollection valid = new CardCollection();
- List players = Lists.newArrayList();
- Player originalTargetPlayer = Iterables.getFirst(getTargetPlayers(chosenSA), null);
- for (final GameEntity o : candidates) {
- if (o instanceof Card) {
- valid.add((Card) o);
- } else if (o instanceof Player) {
- final Player p = (Player) o;
- if (p.equals(originalTargetPlayer))
- continue;
- if (p.isValid(type.split(","), chosenSA.getActivatingPlayer(), chosenSA.getHostCard(), sa)) {
- players.add(p);
+ final List candidates = targetedSA.getTargetRestrictions().getAllCandidates(targetedSA, true);
+ if (sa.hasParam("CanTargetPlayer")) {
+ // Radiate
+ // Remove targeted players because getAllCandidates include all the valid players
+ for(Player p : targetedSA.getTargets().getTargetPlayers())
+ candidates.remove(p);
+
+ for (GameEntity o : candidates) {
+ SpellAbility copy = CardFactory.copySpellAbilityAndPossiblyHost(sa, chosenSA);
+ resetFirstTargetOnCopy(copy, o, targetedSA);
+ copies.add(copy);
+ }
+ } else {// Precursor Golem, Ink-Treader Nephilim
+ final String type = sa.getParam("CopyForEachCanTarget");
+ CardCollection valid = new CardCollection();
+ List players = Lists.newArrayList();
+ Player originalTargetPlayer = Iterables.getFirst(getTargetPlayers(chosenSA), null);
+ for (final GameEntity o : candidates) {
+ if (o instanceof Card) {
+ valid.add((Card) o);
+ } else if (o instanceof Player) {
+ final Player p = (Player) o;
+ if (p.equals(originalTargetPlayer))
+ continue;
+ if (p.isValid(type.split(","), chosenSA.getActivatingPlayer(), chosenSA.getHostCard(), sa)) {
+ players.add(p);
+ }
}
}
- }
- valid = CardLists.getValidCards(valid, type.split(","), chosenSA.getActivatingPlayer(), chosenSA.getHostCard(), sa);
- Card originalTarget = Iterables.getFirst(getTargetCards(chosenSA), null);
- valid.remove(originalTarget);
- mayChooseNewTargets = false;
- if (sa.hasParam("ChooseOnlyOne")) {
- Card choice = controller.getController().chooseSingleEntityForEffect(valid, sa, Localizer.getInstance().getMessage("lblChooseOne"), null);
- SpellAbility copy = CardFactory.copySpellAbilityAndPossiblyHost(card, chosenSA.getHostCard(), chosenSA, true);
- resetFirstTargetOnCopy(copy, choice, targetedSA);
- copies.add(copy);
- } else {
- for (final Card c : valid) {
- SpellAbility copy = CardFactory.copySpellAbilityAndPossiblyHost(card, chosenSA.getHostCard(), chosenSA, true);
+ valid = CardLists.getValidCards(valid, type.split(","), chosenSA.getActivatingPlayer(), chosenSA.getHostCard(), sa);
+ Card originalTarget = Iterables.getFirst(getTargetCards(chosenSA), null);
+ valid.remove(originalTarget);
+
+ if (sa.hasParam("ChooseOnlyOne")) {
+ Card choice = controller.getController().chooseSingleEntityForEffect(valid, sa, Localizer.getInstance().getMessage("lblChooseOne"), null);
+ if (choice != null) {
+ valid = new CardCollection(choice);
+ }
+ }
+
+ for (final Card c : valid) {
+ SpellAbility copy = CardFactory.copySpellAbilityAndPossiblyHost(sa, chosenSA);
resetFirstTargetOnCopy(copy, c, targetedSA);
copies.add(copy);
- }
+ }
+ for (final Player p : players) {
+ SpellAbility copy = CardFactory.copySpellAbilityAndPossiblyHost(sa, chosenSA);
+ resetFirstTargetOnCopy(copy, p, targetedSA);
+ copies.add(copy);
+ }
}
- for (final Player p : players) {
- SpellAbility copy = CardFactory.copySpellAbilityAndPossiblyHost(card, chosenSA.getHostCard(), chosenSA, true);
- resetFirstTargetOnCopy(copy, p, targetedSA);
+ }
+ else {
+ for (int i = 0; i < amount; i++) {
+ SpellAbility copy = CardFactory.copySpellAbilityAndPossiblyHost(sa, chosenSA);
+ if (sa.hasParam("MayChooseTarget")) {
+ copy.setMayChooseNewTargets(true);
+ if (copy.usesTargeting()) {
+ copy.getTargetRestrictions().setMandatory(true);
+ }
+ }
+
+ // extra case for Epic to remove the keyword and the last part of the SpellAbility
+ if (sa.hasParam("Epic")) {
+ copy.getHostCard().removeIntrinsicKeyword("Epic");
+ SpellAbility sub = copy;
+ while (sub.getSubAbility() != null && !sub.hasParam("Epic")) {
+ sub = sub.getSubAbility();
+ }
+ if (sub != null) {
+ sub.getParent().setSubAbility(sub.getSubAbility());
+ }
+ }
+
copies.add(copy);
}
}
- }
- else {
- SpellAbility chosenSA = controller.getController().chooseSingleSpellForEffect(tgtSpells, sa,
- Localizer.getInstance().getMessage("lblSelectASpellCopy"), ImmutableMap.of());
- chosenSA.setActivatingPlayer(controller);
- for (int i = 0; i < amount; i++) {
- SpellAbility copy = CardFactory.copySpellAbilityAndPossiblyHost(
- card, chosenSA.getHostCard(), chosenSA, true);
- // extra case for Epic to remove the keyword and the last part of the SpellAbility
- if (sa.hasParam("Epic")) {
- copy.getHostCard().removeIntrinsicKeyword("Epic");
- SpellAbility sub = copy;
- while (sub.getSubAbility() != null && !sub.hasParam("Epic")) {
- sub = sub.getSubAbility();
- }
- if (sub != null) {
- sub.getParent().setSubAbility(sub.getSubAbility());
- }
+ if (copies.isEmpty()) {
+ continue;
+ }
+
+ int addAmount = copies.size();
+ final Map repParams = AbilityKey.mapFromAffected(controller);
+ repParams.put(AbilityKey.SpellAbility, chosenSA);
+ repParams.put(AbilityKey.Amount, addAmount);
+
+ switch (game.getReplacementHandler().run(ReplacementType.CopySpell, repParams)) {
+ case NotReplaced:
+ break;
+ case Updated: {
+ addAmount = (int) repParams.get(AbilityKey.Amount);
+ break;
+ }
+ default:
+ addAmount = 0;
+ }
+
+ if (addAmount <= 0) {
+ continue;
+ }
+ int extraAmount = addAmount - copies.size();
+ for (int i = 0; i < extraAmount; i++) {
+ SpellAbility copy = CardFactory.copySpellAbilityAndPossiblyHost(sa, chosenSA);
+ // extra copies added with CopySpellReplacenment currently always has new choose targets
+ copy.setMayChooseNewTargets(true);
+ if (copy.usesTargeting()) {
+ copy.getTargetRestrictions().setMandatory(true);
}
-
copies.add(copy);
}
- }
-
- for(SpellAbility copySA : copies) {
- if (mayChooseNewTargets && copySA.usesTargeting()) {
- // TODO: ideally this should be implemented by way of allowing the player to cancel targeting
- // but in that case preserving whatever target was specified for the original spell (since
- // "changing targets" is the optional part).
- copySA.getTargetRestrictions().setMandatory(true);
- }
- controller.getController().playSpellAbilityForFree(copySA, mayChooseNewTargets);
+
+ controller.getController().orderAndPlaySimultaneousSa(copies);
}
} // end resolve
diff --git a/forge-game/src/main/java/forge/game/ability/effects/DelayedTriggerEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DelayedTriggerEffect.java
index 0a95d27b9e2..e91c675d653 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/DelayedTriggerEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/DelayedTriggerEffect.java
@@ -5,7 +5,10 @@ import com.google.common.collect.Maps;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.ability.SpellAbilityEffect;
+import forge.game.card.Card;
+import forge.game.card.CardUtil;
import forge.game.player.Player;
+import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerHandler;
@@ -21,6 +24,8 @@ public class DelayedTriggerEffect extends SpellAbilityEffect {
protected String getStackDescription(SpellAbility sa) {
if (sa.hasParam("TriggerDescription")) {
return sa.getParam("TriggerDescription");
+ } else if (sa.hasParam("SpellDescription")) {
+ return sa.getParam("SpellDescription");
}
return "";
@@ -44,7 +49,8 @@ public class DelayedTriggerEffect extends SpellAbilityEffect {
triggerRemembered = sa.getParam("RememberObjects");
}
- final Trigger delTrig = TriggerHandler.parseTrigger(mapParams, sa.getHostCard(), true);
+ Card lki = CardUtil.getLKICopy(sa.getHostCard());
+ final Trigger delTrig = TriggerHandler.parseTrigger(mapParams, lki, true);
if (triggerRemembered != null) {
for (final String rem : triggerRemembered.split(",")) {
@@ -67,7 +73,9 @@ public class DelayedTriggerEffect extends SpellAbilityEffect {
}
if (mapParams.containsKey("Execute") || sa.hasAdditionalAbility("Execute")) {
- SpellAbility overridingSA = sa.getAdditionalAbility("Execute");
+ AbilitySub overridingSA = (AbilitySub)sa.getAdditionalAbility("Execute").copy(lki, false);
+ // need to reset the parent, additionalAbility does set it to this
+ overridingSA.setParent(null);
overridingSA.setActivatingPlayer(sa.getActivatingPlayer());
overridingSA.setDeltrigActivatingPlayer(sa.getActivatingPlayer()); // ensure that the original activator can be restored later
// Set Transform timestamp when the delayed trigger is created
diff --git a/forge-game/src/main/java/forge/game/ability/effects/PermanentEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PermanentEffect.java
index f916ee8b67e..36437ae9dfb 100644
--- a/forge-game/src/main/java/forge/game/ability/effects/PermanentEffect.java
+++ b/forge-game/src/main/java/forge/game/ability/effects/PermanentEffect.java
@@ -22,6 +22,14 @@ public class PermanentEffect extends SpellAbilityEffect {
sa.getHostCard().setController(p, 0);
final Card host = sa.getHostCard();
+ // 111.11. A copy of a permanent spell becomes a token as it resolves.
+ // The token has the characteristics of the spell that became that token.
+ // The token is not “created” for the purposes of any replacement effects or triggered abilities that refer to creating a token.
+ if (host.isCopiedSpell()) {
+ host.setCopiedSpell(false);
+ host.setToken(true);
+ }
+
final Card c = p.getGame().getAction().moveToPlay(host, p, sa);
sa.setHostCard(c);
diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java
index 1ecff58ab29..7fbc2d9828c 100644
--- a/forge-game/src/main/java/forge/game/card/Card.java
+++ b/forge-game/src/main/java/forge/game/card/Card.java
@@ -3612,8 +3612,8 @@ public class Card extends GameEntity implements Comparable {
if (multiKickerMagnitude > 0) {
return multiKickerMagnitude;
}
- boolean hasK1 = costsPaid.contains(OptionalCost.Kicker1);
- return hasK1 == costsPaid.contains(OptionalCost.Kicker2) ? (hasK1 ? 2 : 0) : 1;
+ boolean hasK1 = isOptionalCostPaid(OptionalCost.Kicker1);
+ return hasK1 == isOptionalCostPaid(OptionalCost.Kicker2) ? (hasK1 ? 2 : 0) : 1;
}
private int pseudoKickerMagnitude = 0;
diff --git a/forge-game/src/main/java/forge/game/card/CardFactory.java b/forge-game/src/main/java/forge/game/card/CardFactory.java
index d73dae2bc8f..1c9162cf4e2 100644
--- a/forge-game/src/main/java/forge/game/card/CardFactory.java
+++ b/forge-game/src/main/java/forge/game/card/CardFactory.java
@@ -125,12 +125,13 @@ public class CardFactory {
* which wouldn't ordinarily get set during a simple Card.copy() call.
*
* */
- private final static Card copySpellHost(final Card source, final Card original, final SpellAbility sa, final boolean bCopyDetails){
- Player controller = sa.getActivatingPlayer();
+ private final static Card copySpellHost(final SpellAbility sourceSA, final SpellAbility targetSA){
+ final Card source = sourceSA.getHostCard();
+ final Card original = targetSA.getHostCard();
+ Player controller = sourceSA.getActivatingPlayer();
final Card c = copyCard(original, true);
// change the color of the copy (eg: Fork)
- final SpellAbility sourceSA = source.getFirstSpellAbility();
if (null != sourceSA && sourceSA.hasParam("CopyIsColor")) {
String tmp = "";
final String newColor = sourceSA.getParam("CopyIsColor");
@@ -148,13 +149,14 @@ public class CardFactory {
c.setOwner(controller);
c.setCopiedSpell(true);
- if (bCopyDetails) {
- c.setXManaCostPaidByColor(original.getXManaCostPaidByColor());
- c.setKickerMagnitude(original.getKickerMagnitude());
+ c.setXManaCostPaidByColor(original.getXManaCostPaidByColor());
+ c.setKickerMagnitude(original.getKickerMagnitude());
- for (OptionalCost cost : original.getOptionalCostsPaid()) {
- c.addOptionalCostPaid(cost);
- }
+ for (OptionalCost cost : original.getOptionalCostsPaid()) {
+ c.addOptionalCostPaid(cost);
+ }
+ if (targetSA.isBestow()) {
+ c.animateBestow();
}
return c;
}
@@ -174,44 +176,33 @@ public class CardFactory {
* @param bCopyDetails
* a boolean.
*/
- public final static SpellAbility copySpellAbilityAndPossiblyHost(final Card source, final Card original, final SpellAbility sa, final boolean bCopyDetails) {
- Player controller = sa.getActivatingPlayer();
+ public final static SpellAbility copySpellAbilityAndPossiblyHost(final SpellAbility sourceSA, final SpellAbility targetSA) {
+ Player controller = sourceSA.getActivatingPlayer();
//it is only necessary to copy the host card if the SpellAbility is a spell, not an ability
- final Card c;
- if (sa.isSpell()){
- c = copySpellHost(source, original, sa, bCopyDetails);
- }
- else {
- c = original;
- }
+ final Card c = targetSA.isSpell() ? copySpellHost(sourceSA, targetSA) : targetSA.getHostCard();
final SpellAbility copySA;
- if (sa.isTrigger() && sa.isWrapper()) {
- copySA = getCopiedTriggeredAbility((WrappedAbility)sa, c);
+ if (targetSA.isTrigger() && targetSA.isWrapper()) {
+ copySA = getCopiedTriggeredAbility((WrappedAbility)targetSA, c);
} else {
- copySA = sa.copy(c, false);
- }
-
- if (sa.isSpell()){
- //only update c's abilities if c is a copy.
- //(it would be nice to move this into `copySpellHost`,
- // so all the c-mutating code is together in one place.
- // but copySA doesn't exist until after `copySpellHost` finishes executing,
- // so it's hard to resolve that dependency.)
- c.getCurrentState().setNonManaAbilities(copySA);
+ copySA = targetSA.copy(c, false);
}
copySA.setCopied(true);
+
+ if (targetSA.usesTargeting()) {
+ // do for SubAbilities too?
+ copySA.setTargets(targetSA.getTargets().clone());
+ }
+
//remove all costs
if (!copySA.isTrigger()) {
- copySA.setPayCosts(new Cost("", sa.isAbility()));
+ copySA.setPayCosts(new Cost("", targetSA.isAbility()));
}
copySA.setActivatingPlayer(controller);
- if (bCopyDetails) {
- copySA.setPaidHash(sa.getPaidHash());
- }
+ copySA.setPaidHash(targetSA.getPaidHash());
return copySA;
}
diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java
index d4a7bb506bf..8c016cfbc2e 100644
--- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java
+++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java
@@ -2434,7 +2434,7 @@ public class CardFactoryUtil {
inst.addTrigger(parsedTrigReturn);
} else if (keyword.equals("Conspire")) {
final String trigScript = "Mode$ SpellCast | ValidCard$ Card.Self | CheckSVar$ Conspire | Secondary$ True | TriggerDescription$ Copy CARDNAME if its conspire cost was paid";
- final String abString = "DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ 1";
+ final String abString = "DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ 1 | MayChooseTarget$ True";
final Trigger conspireTrigger = TriggerHandler.parseTrigger(trigScript, card, intrinsic);
conspireTrigger.setOverridingAbility(AbilityFactory.getAbility(abString, card));
@@ -2630,6 +2630,18 @@ public class CardFactoryUtil {
trigger.setOverridingAbility(AbilityFactory.getAbility(sb.toString(), card));
+ inst.addTrigger(trigger);
+ } else if (keyword.startsWith("Gravestorm")) {
+ String trigStr = "Mode$ SpellCast | ValidCard$ Card.Self | TriggerDescription$ Gravestorm (" + inst.getReminderText() + ")";
+ String copyStr = "DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ GravestormCount | MayChooseTarget$ True";
+
+ SpellAbility copySa = AbilityFactory.getAbility(copyStr, card);
+ copySa.setSVar("GravestormCount", "Count$ThisTurnEntered_Graveyard_from_Battlefield_Permanent");
+
+ final Trigger trigger = TriggerHandler.parseTrigger(trigStr, card, intrinsic);
+
+ trigger.setOverridingAbility(copySa);
+
inst.addTrigger(trigger);
} else if (keyword.startsWith("Haunt")) {
final String[] k = keyword.split(":");
@@ -3069,7 +3081,7 @@ public class CardFactoryUtil {
inst.addTrigger(myTrigger);
} else if (keyword.startsWith("Replicate")) {
final String trigScript = "Mode$ SpellCast | ValidCard$ Card.Self | CheckSVar$ ReplicateAmount | Secondary$ True | TriggerDescription$ Copy CARDNAME for each time you paid its replicate cost";
- final String abString = "DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ ReplicateAmount";
+ final String abString = "DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ ReplicateAmount | MayChooseTarget$ True";
final Trigger replicateTrigger = TriggerHandler.parseTrigger(trigScript, card, intrinsic);
final SpellAbility replicateAbility = AbilityFactory.getAbility(abString, card);
@@ -3197,7 +3209,7 @@ public class CardFactoryUtil {
final String actualTrigger = "Mode$ SpellCast | ValidCard$ Card.Self | Secondary$ True"
+ "| TriggerDescription$ Storm (" + inst.getReminderText() + ")";
- String effect = "DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ StormCount";
+ String effect = "DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ StormCount | MayChooseTarget$ True";
final Trigger parsedTrigger = TriggerHandler.parseTrigger(actualTrigger, card, intrinsic);
diff --git a/forge-game/src/main/java/forge/game/keyword/Keyword.java b/forge-game/src/main/java/forge/game/keyword/Keyword.java
index bcf60c0a504..920188cef56 100644
--- a/forge-game/src/main/java/forge/game/keyword/Keyword.java
+++ b/forge-game/src/main/java/forge/game/keyword/Keyword.java
@@ -74,7 +74,7 @@ public enum Keyword {
FORTIFY("Fortify", KeywordWithCost.class, false, "%s: Attach to target land you control. Fortify only as a sorcery."),
FRENZY("Frenzy", KeywordWithAmount.class, false, "Whenever this creature attacks and isn't blocked, it gets +%d/+0 until end of turn."),
GRAFT("Graft", KeywordWithAmount.class, false, "This permanent enters the battlefield with {%d:+1/+1 counter} on it. Whenever another creature enters the battlefield, you may move a +1/+1 counter from this permanent onto it."),
- GRAVESTORM("Gravestorm", SimpleKeyword.class, false, "When you cast this spell, copy it for each permanent that was put into a graveyard from the battlefield this turn. You may choose new targets for the copies."),
+ GRAVESTORM("Gravestorm", SimpleKeyword.class, false, "When you cast this spell, copy it for each permanent that was put into a graveyard from the battlefield this turn. If the spell has any targets, you may choose new targets for any of the copies."),
HASTE("Haste", SimpleKeyword.class, true, "This creature can attack and {T} as soon as it comes under your control."),
HAUNT("Haunt", SimpleKeyword.class, false, "When this is put into a graveyard, exile it haunting target creature."),
HEXPROOF("Hexproof", Hexproof.class, false, "This can't be the target of %s spells or abilities your opponents control."),
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceCopySpell.java b/forge-game/src/main/java/forge/game/replacement/ReplaceCopySpell.java
new file mode 100644
index 00000000000..7fec930bf0a
--- /dev/null
+++ b/forge-game/src/main/java/forge/game/replacement/ReplaceCopySpell.java
@@ -0,0 +1,43 @@
+package forge.game.replacement;
+
+import java.util.Map;
+
+import forge.game.ability.AbilityKey;
+import forge.game.card.Card;
+import forge.game.spellability.SpellAbility;
+
+public class ReplaceCopySpell extends ReplacementEffect {
+
+ public ReplaceCopySpell(Map map, Card host, boolean intrinsic) {
+ super(map, host, intrinsic);
+ }
+
+ /* (non-Javadoc)
+ * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.Map)
+ */
+ @Override
+ public boolean canReplace(Map runParams) {
+ if (((int) runParams.get(AbilityKey.Amount)) <= 0) {
+ return false;
+ }
+ if (hasParam("ValidPlayer")) {
+ if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), getHostCard())) {
+ return false;
+ }
+ }
+ if (hasParam("ValidSpell")) {
+ if (!matchesValid(runParams.get(AbilityKey.SpellAbility), getParam("ValidSpell").split(","), getHostCard())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
+ */
+ @Override
+ public void setReplacingObjects(Map runParams, SpellAbility sa) {
+ sa.setReplacingObject(AbilityKey.Amount, runParams.get(AbilityKey.Amount));
+ }
+}
diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementType.java b/forge-game/src/main/java/forge/game/replacement/ReplacementType.java
index c13b3f172d0..88f55ebe554 100644
--- a/forge-game/src/main/java/forge/game/replacement/ReplacementType.java
+++ b/forge-game/src/main/java/forge/game/replacement/ReplacementType.java
@@ -14,6 +14,7 @@ public enum ReplacementType {
AddCounter(ReplaceAddCounter.class),
Attached(ReplaceAttached.class),
Counter(ReplaceCounter.class),
+ CopySpell(ReplaceCopySpell.class),
CreateToken(ReplaceToken.class),
DamageDone(ReplaceDamage.class),
Destroy(ReplaceDestroy.class),
diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java
index 70be5f60696..ed48b7562b2 100644
--- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java
+++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java
@@ -43,6 +43,7 @@ import forge.game.cost.CostRemoveCounter;
import forge.game.keyword.Keyword;
import forge.game.mana.Mana;
import forge.game.player.Player;
+import forge.game.player.PlayerCollection;
import forge.game.replacement.ReplacementEffect;
import forge.game.staticability.StaticAbility;
import forge.game.trigger.Trigger;
@@ -52,6 +53,7 @@ import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import forge.util.Expressions;
import forge.util.TextUtil;
+
import org.apache.commons.lang3.StringUtils;
import java.util.*;
@@ -148,6 +150,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
private boolean undoable;
private boolean isCopied = false;
+ private boolean mayChooseNewTargets = false;
private EnumSet optionalCosts = EnumSet.noneOf(OptionalCost.class);
private TargetRestrictions targetRestrictions = null;
@@ -863,6 +866,9 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
copyHelper(clone, host);
+ // always set this to false, it is only set in CopyEffect
+ clone.mayChooseNewTargets = false;
+
clone.triggeringObjects = AbilityKey.newMap(this.triggeringObjects);
clone.setPayCosts(getPayCosts().copy());
@@ -884,6 +890,11 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
clone.setPaidHash(Maps.newHashMap(getPaidHash()));
+ if (usesTargeting()) {
+ // the targets need to be cloned, otherwise they might be cleared
+ clone.targetChosen = getTargets().clone();
+ }
+
// clear maps for copy, the values will be added later
clone.additionalAbilities = Maps.newHashMap();
clone.additionalAbilityLists = Maps.newHashMap();
@@ -1287,6 +1298,13 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
}
}
+ public boolean isMayChooseNewTargets() {
+ return mayChooseNewTargets;
+ }
+ public void setMayChooseNewTargets(boolean value) {
+ mayChooseNewTargets = value;
+ }
+
/**
* Returns whether variable was present in the announce list.
*/
@@ -1358,6 +1376,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
}
public void setTargets(TargetChoices targets) {
+ // TODO should copy the target choices?
targetChosen = targets;
}
@@ -1656,6 +1675,48 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
return p != null && p.isTargeting(o);
}
+ public boolean setupTargets() {
+ // Skip to paying if parent ability doesn't target and has no subAbilities.
+ // (or trigger case where its already targeted)
+ SpellAbility currentAbility = this;
+ final Card source = getHostCard();
+ do {
+ final TargetRestrictions tgt = currentAbility.getTargetRestrictions();
+ if (tgt != null && tgt.doesTarget()) {
+ currentAbility.clearTargets();
+ Player targetingPlayer;
+ if (currentAbility.hasParam("TargetingPlayer")) {
+ final PlayerCollection candidates = AbilityUtils.getDefinedPlayers(source, currentAbility.getParam("TargetingPlayer"), currentAbility);
+ // activator chooses targeting player
+ targetingPlayer = getActivatingPlayer().getController().chooseSingleEntityForEffect(
+ candidates, currentAbility, "Choose the targeting player", null);
+ } else {
+ targetingPlayer = getActivatingPlayer();
+ }
+ currentAbility.setTargetingPlayer(targetingPlayer);
+ if (!targetingPlayer.getController().chooseTargetsFor(currentAbility)) {
+ return false;
+ }
+ }
+ final AbilitySub subAbility = currentAbility.getSubAbility();
+ if (subAbility != null) {
+ // This is necessary for "TargetsWithDefinedController$ ParentTarget"
+ subAbility.setParent(currentAbility);
+ }
+ currentAbility = subAbility;
+ } while (currentAbility != null);
+ return true;
+ }
+ public final void clearTargets() {
+ final TargetRestrictions tg = getTargetRestrictions();
+ if (tg != null) {
+ resetTargets();
+ if (hasParam("DividedAsYouChoose")) {
+ tg.calculateStillToDivide(getParam("DividedAsYouChoose"), getHostCard(), this);
+ }
+ }
+ }
+
// Takes one argument like Permanent.Blue+withFlying
@Override
public final boolean isValid(final String restriction, final Player sourceController, final Card source, SpellAbility spellAbility) {
diff --git a/forge-game/src/main/java/forge/game/spellability/TargetChoices.java b/forge-game/src/main/java/forge/game/spellability/TargetChoices.java
index 1559a847038..500e469f707 100644
--- a/forge-game/src/main/java/forge/game/spellability/TargetChoices.java
+++ b/forge-game/src/main/java/forge/game/spellability/TargetChoices.java
@@ -25,6 +25,7 @@ import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.player.Player;
+import forge.game.player.PlayerCollection;
import java.util.ArrayList;
import java.util.List;
@@ -42,7 +43,7 @@ public class TargetChoices implements Cloneable {
// Card or Player are legal targets.
private final CardCollection targetCards = new CardCollection();
- private final List targetPlayers = new ArrayList<>();
+ private final PlayerCollection targetPlayers = new PlayerCollection();
private final List targetSpells = new ArrayList<>();
public final int getNumTargeted() {
@@ -70,8 +71,7 @@ public class TargetChoices implements Cloneable {
}
private final boolean addTarget(final Card c) {
- if (!targetCards.contains(c)) {
- targetCards.add(c);
+ if (targetCards.add(c)) {
numTargeted++;
return true;
}
@@ -79,8 +79,7 @@ public class TargetChoices implements Cloneable {
}
private final boolean addTarget(final Player p) {
- if (!targetPlayers.contains(p)) {
- targetPlayers.add(p);
+ if (targetPlayers.add(p)) {
numTargeted++;
return true;
}
@@ -213,16 +212,10 @@ public class TargetChoices implements Cloneable {
if (obj instanceof TargetChoices) {
TargetChoices compare = (TargetChoices)obj;
- if (this.getNumTargeted() != compare.getNumTargeted()) {
+ if (getNumTargeted() != compare.getNumTargeted()) {
return false;
}
- for (int i = 0; i < this.getTargets().size(); i++) {
- if (!compare.getTargets().get(i).equals(this.getTargets().get(i))) {
- return false;
- }
- }
- return true;
-
+ return getTargets().equals(compare.getTargets());
} else {
return false;
}
diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java b/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java
index 24a7e1e6feb..59d7aa47a7a 100644
--- a/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java
+++ b/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java
@@ -516,10 +516,17 @@ public class TriggerHandler {
else {
// get CardState does not work for transformed cards
// also its about LKI
+ // TODO remove this part after all spellAbility can handle LKI as host
+ // Currently only true for delayed Trigger
if (host.isInZone(ZoneType.Battlefield) || !host.hasAlternateState()) {
// if host changes Zone with other cards, try to use original host
- if (!regtrig.getMode().equals(TriggerType.ChangesZone))
- host = game.getCardState(host);
+ if (!regtrig.getMode().equals(TriggerType.ChangesZone)) {
+ Card gameHost = game.getCardState(host);
+ // TODO only set when the host equals the game state
+ if (gameHost.equalsWithTimestamp(host)) {
+ host = gameHost;
+ }
+ }
}
}
diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerSpellAbilityCast.java b/forge-game/src/main/java/forge/game/trigger/TriggerSpellAbilityCast.java
index bf5e16496c9..7ac0c404c5c 100644
--- a/forge-game/src/main/java/forge/game/trigger/TriggerSpellAbilityCast.java
+++ b/forge-game/src/main/java/forge/game/trigger/TriggerSpellAbilityCast.java
@@ -269,7 +269,7 @@ public class TriggerSpellAbilityCast extends Trigger {
final SpellAbility castSA = (SpellAbility) runParams.get(AbilityKey.CastSA);
final SpellAbilityStackInstance si = sa.getHostCard().getGame().getStack().getInstanceFromSpellAbility(castSA);
sa.setTriggeringObject(AbilityKey.Card, castSA.getHostCard());
- sa.setTriggeringObject(AbilityKey.SpellAbility, castSA);
+ sa.setTriggeringObject(AbilityKey.SpellAbility, castSA.copy(castSA.getHostCard(), true));
sa.setTriggeringObject(AbilityKey.StackInstance, si);
sa.setTriggeringObject(AbilityKey.SpellAbilityTargetingCards, (si != null ? si.getSpellAbility(true) : castSA).getTargets().getTargetCards());
sa.setTriggeringObjectsFrom(
diff --git a/forge-game/src/main/java/forge/game/zone/MagicStack.java b/forge-game/src/main/java/forge/game/zone/MagicStack.java
index d5c174b5e86..ddc426ac2e9 100644
--- a/forge-game/src/main/java/forge/game/zone/MagicStack.java
+++ b/forge-game/src/main/java/forge/game/zone/MagicStack.java
@@ -6,12 +6,12 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
@@ -65,7 +65,7 @@ import forge.util.TextUtil;
*
* MagicStack class.
*
- *
+ *
* @author Forge
* @version $Id$
*/
@@ -135,14 +135,12 @@ public class MagicStack /* extends MyObservable */ implements Iterable runParams = AbilityKey.newMap();
- if (!(sp instanceof AbilityStatic) && !sp.isCopied()) {
+ if (!sp.isCopied()) {
// Run SpellAbilityCast triggers
runParams.put(AbilityKey.Cost, sp.getPayCosts());
runParams.put(AbilityKey.Player, sp.getHostCard().getController());
@@ -322,17 +322,15 @@ public class MagicStack /* extends MyObservable */ implements Iterable chosenTargets = sp.getAllTargetChoices();
- if (!chosenTargets.isEmpty()) {
+ if (!chosenTargets.isEmpty()) {
runParams = Maps.newHashMap();
SpellAbility s = sp;
if (si != null) {
@@ -362,7 +360,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable params = AbilityKey.newMap();
@@ -864,8 +869,8 @@ public class MagicStack /* extends MyObservable */ implements Iterable {
if (!c.isImmutable()) {
final Zone oldZone = game.getZoneOf(c);
final ZoneType zt = oldZone == null ? ZoneType.Stack : oldZone.getZoneType();
- cardsAddedThisTurn.add(zt, c);
- latestStateCardsAddedThisTurn.add(zt, latestState != null ? latestState : c);
+
+ // only if the zoneType differss from this
+ if (zt != zoneType) {
+ cardsAddedThisTurn.add(zt, c);
+ latestStateCardsAddedThisTurn.add(zt, latestState != null ? latestState : c);
+ }
}
c.setTurnInZone(game.getPhaseHandler().getTurn());
diff --git a/forge-gui/res/cardsfolder/b/banish_into_fable.txt b/forge-gui/res/cardsfolder/b/banish_into_fable.txt
index 4aab936b038..8caa824e1f4 100644
--- a/forge-gui/res/cardsfolder/b/banish_into_fable.txt
+++ b/forge-gui/res/cardsfolder/b/banish_into_fable.txt
@@ -2,8 +2,9 @@ Name:Banish into Fable
ManaCost:4 W U
Types:Instant
T:Mode$ SpellCast | ValidCard$ Card.Self+wasCastFromHand | Execute$ TrigCopy | TriggerDescription$ When you cast this spell from your hand, copy it if you control an artifact, then copy it if you control an enchantment. You may choose new targets for the copies.
-SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | ConditionPresent$ Artifact.YouCtrl | ConditionCompare$ GE1 | SubAbility$ DBCopy
-SVar:DBCopy:DB$ CopySpellAbility| Defined$ TriggeredSpellAbility | ConditionPresent$ Enchantment.YouCtrl | ConditionCompare$ GE1
+# TODO check ruling with Twinning Staff
+SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | ConditionPresent$ Artifact.YouCtrl | ConditionCompare$ GE1 | MayChooseTarget$ True | SubAbility$ DBCopy
+SVar:DBCopy:DB$ CopySpellAbility| Defined$ TriggeredSpellAbility | ConditionPresent$ Enchantment.YouCtrl | ConditionCompare$ GE1 | MayChooseTarget$ True
A:SP$ ChangeZone | Cost$ 4 W U | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | Origin$ Battlefield | Destination$ Hand | SubAbility$ DBToken | SpellDescription$ Return target nonland permanent to its owner's hand. You create a 2/2 white Knight creature token with vigilance.
SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_2_2_knight_vigilance | TokenOwner$ You | LegacyImage$ w 2 2 knight vigilance eld
DeckHas:Ability$Token
diff --git a/forge-gui/res/cardsfolder/b/bitter_ordeal.txt b/forge-gui/res/cardsfolder/b/bitter_ordeal.txt
index f089956ebb1..b2cedbcc4a1 100644
--- a/forge-gui/res/cardsfolder/b/bitter_ordeal.txt
+++ b/forge-gui/res/cardsfolder/b/bitter_ordeal.txt
@@ -2,8 +2,5 @@ Name:Bitter Ordeal
ManaCost:2 B
Types:Sorcery
A:SP$ ChangeZone | Cost$ 2 B | Origin$ Library | Destination$ Exile | ValidTgts$ Player | ChangeType$ Card | ChangeNum$ 1 | IsCurse$ True | SpellDescription$ Search target player's library for a card and exile it. Then that player shuffles their library.
-T:Mode$ SpellCast | ValidCard$ Card.Self | Execute$ TrigGravestorm | TriggerDescription$ Gravestorm (When you cast this spell, copy it for each permanent put into a graveyard this turn. You may choose new targets for the copies.)
-SVar:TrigGravestorm:DB$CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ GravestormCount | References$ GravestormCount
-SVar:GravestormCount:Count$ThisTurnEntered_Graveyard_Permanent
-SVar:Picture:http://www.wizards.com/global/images/magic/general/bitter_ordeal.jpg
-Oracle:Search target player's library for a card and exile it. Then that player shuffles their library.\nGravestorm (When you cast this spell, copy it for each permanent put into a graveyard this turn. You may choose new targets for the copies.)
+K:Gravestorm
+Oracle:Search target player's library for a card and exile it. Then that player shuffles their library.\nGravestorm (When you cast this spell, copy it for each permanent that was put into a graveyard from the battlefield this turn. If the spell has any targets, you may choose new targets for any of the copies.)
diff --git a/forge-gui/res/cardsfolder/b/bonus_round.txt b/forge-gui/res/cardsfolder/b/bonus_round.txt
index 0cce52c3efd..bc199264cd0 100644
--- a/forge-gui/res/cardsfolder/b/bonus_round.txt
+++ b/forge-gui/res/cardsfolder/b/bonus_round.txt
@@ -3,7 +3,7 @@ ManaCost:1 R R
Types:Sorcery
A:SP$ Effect | Cost$ 1 R R | Name$ Bonus Round Effect | Triggers$ TrigSpellCast | SVars$ TrigCopySpell | SpellDescription$ Until end of turn, whenever a player casts an instant or sorcery spell, that player copies it and may choose new targets for the copy.
SVar:TrigSpellCast:Mode$ SpellCast | ValidCard$ Instant,Sorcery | TriggerZones$ Command | ValidActivatingPlayer$ Player | Execute$ TrigCopySpell | TriggerDescription$ Until end of turn, whenever a player casts an instant or sorcery spell, that player copies it and may choose new targets for the copy.
-SVar:TrigCopySpell:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | AILogic$ Always | Controller$ TriggeredCardController
+SVar:TrigCopySpell:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | AILogic$ Always | Controller$ TriggeredCardController | MayChooseTarget$ True
DeckNeeds:Type$Instant|Sorcery
AI:RemoveDeck:Random
SVar:PlayMain1:TRUE
diff --git a/forge-gui/res/cardsfolder/c/chain_lightning.txt b/forge-gui/res/cardsfolder/c/chain_lightning.txt
index b5045e1c9bf..7855ba374ec 100644
--- a/forge-gui/res/cardsfolder/c/chain_lightning.txt
+++ b/forge-gui/res/cardsfolder/c/chain_lightning.txt
@@ -2,7 +2,5 @@ Name:Chain Lightning
ManaCost:R
Types:Sorcery
A:SP$ DealDamage | Cost$ R | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select target | NumDmg$ 3 | SubAbility$ DBCopy1 | SpellDescription$ CARDNAME deals 3 damage to any target. Then that player or that permanent's controller may pay {R}{R}. If the player does, they may copy this spell and may choose a new target for that copy.
-SVar:DBCopy1:DB$ CopySpellAbility | Defined$ Parent | Controller$ TargetedController | UnlessPayer$ TargetedController | UnlessCost$ R R | UnlessSwitched$ True | ConditionDefined$ Targeted | ConditionPresent$ Permanent | ConditionCompare$ GE1 | SubAbility$ DBCopy2 | StackDescription$ None
-SVar:DBCopy2:DB$ CopySpellAbility | Defined$ Parent | Controller$ Targeted | UnlessPayer$ Targeted | UnlessCost$ R R | UnlessSwitched$ True | ConditionDefined$ Targeted | ConditionPresent$ Permanent | ConditionCompare$ EQ0 | StackDescription$ None
-SVar:Picture:http://www.wizards.com/global/images/magic/general/chain_lightning.jpg
+SVar:DBCopy1:DB$ CopySpellAbility | Defined$ Parent | Controller$ TargetedOrController | UnlessPayer$ TargetedOrController | UnlessCost$ R R | UnlessSwitched$ True | MayChooseTarget$ True | StackDescription$ None
Oracle:Chain Lightning deals 3 damage to any target. Then that player or that permanent's controller may pay {R}{R}. If the player does, they may copy this spell and may choose a new target for that copy.
diff --git a/forge-gui/res/cardsfolder/c/chain_of_acid.txt b/forge-gui/res/cardsfolder/c/chain_of_acid.txt
index 2a69c266dcd..70f09a1ca7c 100644
--- a/forge-gui/res/cardsfolder/c/chain_of_acid.txt
+++ b/forge-gui/res/cardsfolder/c/chain_of_acid.txt
@@ -2,7 +2,6 @@ Name:Chain of Acid
ManaCost:3 G
Types:Sorcery
A:SP$ Destroy | Cost$ 3 G | ValidTgts$ Permanent.nonCreature | SubAbility$ DBCopy | SpellDescription$ Destroy target noncreature permanent. Then that permanent's controller may copy this spell and may choose a new target for that copy.
-SVar:DBCopy:DB$ CopySpellAbility | Defined$ Parent | Controller$ TargetedController | Optional$ True | AILogic$ ChainOfAcid | StackDescription$ None
+SVar:DBCopy:DB$ CopySpellAbility | Defined$ Parent | Controller$ TargetedController | Optional$ True | AILogic$ ChainOfAcid | StackDescription$ None | MayChooseTarget$ True
AI:RemoveDeck:Random
-SVar:Picture:http://www.wizards.com/global/images/magic/general/chain_of_acid.jpg
-Oracle:Destroy target noncreature permanent. Then that permanent's controller may copy this spell and may choose a new target for that copy.
\ No newline at end of file
+Oracle:Destroy target noncreature permanent. Then that permanent's controller may copy this spell and may choose a new target for that copy.
diff --git a/forge-gui/res/cardsfolder/c/chain_of_plasma.txt b/forge-gui/res/cardsfolder/c/chain_of_plasma.txt
index 8eea0a87f49..075b8756c46 100644
--- a/forge-gui/res/cardsfolder/c/chain_of_plasma.txt
+++ b/forge-gui/res/cardsfolder/c/chain_of_plasma.txt
@@ -2,7 +2,5 @@ Name:Chain of Plasma
ManaCost:1 R
Types:Instant
A:SP$ DealDamage | Cost$ 1 R | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ 3 | SubAbility$ DBCopy1 | SpellDescription$ CARDNAME deals 3 damage to any target. Then that player or that permanent's controller may discard a card. If the player does, they may copy this spell and may choose a new target for that copy.
-SVar:DBCopy1:DB$ CopySpellAbility | Defined$ Parent | Controller$ TargetedController | UnlessPayer$ TargetedController | UnlessCost$ Discard<1/Card> | UnlessSwitched$ True | ConditionDefined$ Targeted | ConditionPresent$ Permanent | ConditionCompare$ GE1 | SubAbility$ DBCopy2 | StackDescription$ None
-SVar:DBCopy2:DB$ CopySpellAbility | Defined$ Parent | Controller$ Targeted | UnlessPayer$ Targeted | UnlessCost$ Discard<1/Card> | UnlessSwitched$ True | ConditionDefined$ Targeted | ConditionPresent$ Permanent | ConditionCompare$ EQ0 | StackDescription$ None
-SVar:Picture:http://www.wizards.com/global/images/magic/general/chain_of_plasma.jpg
+SVar:DBCopy1:DB$ CopySpellAbility | Defined$ Parent | Controller$ TargetedOrController | UnlessPayer$ TargetedOrController | UnlessCost$ Discard<1/Card> | UnlessSwitched$ True | StackDescription$ None | MayChooseTarget$ True
Oracle:Chain of Plasma deals 3 damage to any target. Then that player or that permanent's controller may discard a card. If the player does, they may copy this spell and may choose a new target for that copy.
diff --git a/forge-gui/res/cardsfolder/c/chain_of_silence.txt b/forge-gui/res/cardsfolder/c/chain_of_silence.txt
index c19c6a5f5b4..451adee2b8d 100644
--- a/forge-gui/res/cardsfolder/c/chain_of_silence.txt
+++ b/forge-gui/res/cardsfolder/c/chain_of_silence.txt
@@ -2,6 +2,5 @@ Name:Chain of Silence
ManaCost:1 W
Types:Instant
A:SP$ Pump | Cost$ 1 W | ValidTgts$ Creature | KW$ Prevent all damage that would be dealt by CARDNAME. | IsCurse$ True | TgtPrompt$ Select target creature | SubAbility$ DBCopy | SpellDescription$ Prevent all damage target creature would deal this turn. That creature's controller may sacrifice a land. If the player does, they may copy this spell and may choose a new target for that copy. | StackDescription$ SpellDescription
-SVar:DBCopy:DB$ CopySpellAbility | Defined$ Parent | Controller$ TargetedController | Optional$ True | UnlessPayer$ TargetedController | UnlessCost$ Sac<1/Land> | UnlessSwitched$ True | UnlessAI$ Never | StackDescription$ None
-SVar:Picture:http://www.wizards.com/global/images/magic/general/chain_of_silence.jpg
-Oracle:Prevent all damage target creature would deal this turn. That creature's controller may sacrifice a land. If the player does, they may copy this spell and may choose a new target for that copy.
\ No newline at end of file
+SVar:DBCopy:DB$ CopySpellAbility | Defined$ Parent | Controller$ TargetedController | Optional$ True | UnlessPayer$ TargetedController | UnlessCost$ Sac<1/Land> | UnlessSwitched$ True | UnlessAI$ Never | StackDescription$ None | MayChooseTarget$ True
+Oracle:Prevent all damage target creature would deal this turn. That creature's controller may sacrifice a land. If the player does, they may copy this spell and may choose a new target for that copy.
diff --git a/forge-gui/res/cardsfolder/c/chain_of_smog.txt b/forge-gui/res/cardsfolder/c/chain_of_smog.txt
index 6b210fded18..1fc9b650df1 100644
--- a/forge-gui/res/cardsfolder/c/chain_of_smog.txt
+++ b/forge-gui/res/cardsfolder/c/chain_of_smog.txt
@@ -2,7 +2,6 @@ Name:Chain of Smog
ManaCost:1 B
Types:Sorcery
A:SP$ Discard | Cost$ 1 B | ValidTgts$ Player | NumCards$ 2 | Mode$ TgtChoose | SubAbility$ DBCopy | SpellDescription$ Target player discards two cards. That player may copy this spell and may choose a new target for that copy.
-SVar:DBCopy:DB$ CopySpellAbility | Defined$ Parent | Controller$ TargetedPlayer | Optional$ True | AILogic$ ChainOfSmog | StackDescription$ None
+SVar:DBCopy:DB$ CopySpellAbility | Defined$ Parent | Controller$ TargetedPlayer | Optional$ True | AILogic$ ChainOfSmog | StackDescription$ None | MayChooseTarget$ True
AI:RemoveDeck:Random
-SVar:Picture:http://www.wizards.com/global/images/magic/general/chain_of_smog.jpg
Oracle:Target player discards two cards. That player may copy this spell and may choose a new target for that copy.
diff --git a/forge-gui/res/cardsfolder/c/chain_of_vapor.txt b/forge-gui/res/cardsfolder/c/chain_of_vapor.txt
index 4f3beaa6432..1ac6f4ae8c1 100644
--- a/forge-gui/res/cardsfolder/c/chain_of_vapor.txt
+++ b/forge-gui/res/cardsfolder/c/chain_of_vapor.txt
@@ -2,6 +2,5 @@ Name:Chain of Vapor
ManaCost:U
Types:Instant
A:SP$ ChangeZone | Cost$ U | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | Origin$ Battlefield | Destination$ Hand | SubAbility$ DBCopy | StackDescription$ SpellDescription | SpellDescription$ Return target nonland permanent to its owner's hand. Then that permanent's controller may sacrifice a land. If the player does, they may copy this spell and may choose a new target for that copy.
-SVar:DBCopy:DB$ CopySpellAbility | Defined$ Parent | Controller$ TargetedController | UnlessPayer$ TargetedController | UnlessCost$ Sac<1/Land> | UnlessSwitched$ True | StackDescription$ None
-SVar:Picture:http://www.wizards.com/global/images/magic/general/chain_of_vapor.jpg
+SVar:DBCopy:DB$ CopySpellAbility | Defined$ Parent | Controller$ TargetedController | UnlessPayer$ TargetedController | UnlessCost$ Sac<1/Land> | UnlessSwitched$ True | StackDescription$ None | MayChooseTarget$ True
Oracle:Return target nonland permanent to its owner's hand. Then that permanent's controller may sacrifice a land. If the player does, they may copy this spell and may choose a new target for that copy.
diff --git a/forge-gui/res/cardsfolder/c/chain_stasis.txt b/forge-gui/res/cardsfolder/c/chain_stasis.txt
index 9a7571977e6..65baa729377 100644
--- a/forge-gui/res/cardsfolder/c/chain_stasis.txt
+++ b/forge-gui/res/cardsfolder/c/chain_stasis.txt
@@ -2,7 +2,6 @@ Name:Chain Stasis
ManaCost:U
Types:Instant
A:SP$ TapOrUntap | Cost$ U | ValidTgts$ Creature | TgtPrompt$ Select target creature | SubAbility$ DBCopy | SpellDescription$ You may tap or untap target creature. Then that creature's controller may pay {2}{U}. If the player does, they may copy this spell and may choose a new target for that copy.
-SVar:DBCopy:DB$ CopySpellAbility | Defined$ Parent | Controller$ TargetedController | UnlessPayer$ TargetedController | UnlessCost$ 2 U | UnlessSwitched$ True | StackDescription$ Then that creature's controller may pay {2}{U}. If the player does, they may copy this spell and may choose a new target for that copy.
+SVar:DBCopy:DB$ CopySpellAbility | Defined$ Parent | Controller$ TargetedController | UnlessPayer$ TargetedController | UnlessCost$ 2 U | UnlessSwitched$ True | MayChooseTarget$ True | StackDescription$ Then that creature's controller may pay {2}{U}. If the player does, they may copy this spell and may choose a new target for that copy.
AI:RemoveDeck:All
-SVar:Picture:http://www.wizards.com/global/images/magic/general/chain_stasis.jpg
Oracle:You may tap or untap target creature. Then that creature's controller may pay {2}{U}. If the player does, they may copy this spell and may choose a new target for that copy.
diff --git a/forge-gui/res/cardsfolder/c/chandra_the_firebrand.txt b/forge-gui/res/cardsfolder/c/chandra_the_firebrand.txt
index 10e65e21df6..bdcf9a769e7 100644
--- a/forge-gui/res/cardsfolder/c/chandra_the_firebrand.txt
+++ b/forge-gui/res/cardsfolder/c/chandra_the_firebrand.txt
@@ -2,11 +2,8 @@ Name:Chandra, the Firebrand
ManaCost:3 R
Types:Legendary Planeswalker Chandra
Loyalty:3
-A:AB$DealDamage | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ 1 | SpellDescription$ CARDNAME deals 1 damage to any target.
-A:AB$Effect | Cost$ SubCounter<2/LOYALTY> | Planeswalker$ True | AILogic$ SpellCopy | Name$ Chandra, the Firebrand effect. | Image$ chandra_the_firebrand_effect | Triggers$ TrigCopy | SVars$ TrigCopyMain,DBCleanup | SpellDescription$ When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.
-A:AB$DealDamage | Cost$ SubCounter<6/LOYALTY> | Planeswalker$ True | Ultimate$ True | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | TargetMin$ 0 | TargetMax$ 6 | NumDmg$ 6 | SpellDescription$ CARDNAME deals 6 damage to each of up to six targets.
-SVar:TrigCopy:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | OneOff$ True | Execute$ TrigCopyMain | TriggerZones$ Command | TriggerDescription$ When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.
-SVar:TrigCopyMain:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | SubAbility$ DBCleanup
-SVar:DBCleanup:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
-SVar:Picture:http://www.wizards.com/global/images/magic/general/chandra_the_firebrand.jpg
+A:AB$ DealDamage | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ 1 | SpellDescription$ CARDNAME deals 1 damage to any target.
+A:AB$ DelayedTrigger | Cost$ SubCounter<2/LOYALTY> | Planeswalker$ True | AILogic$ SpellCopy | Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | ThisTurn$ True | Execute$ EffTrigCopy | SpellDescription$ When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.
+SVar:EffTrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
+A:AB$ DealDamage | Cost$ SubCounter<6/LOYALTY> | Planeswalker$ True | Ultimate$ True | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | TargetMin$ 0 | TargetMax$ 6 | NumDmg$ 6 | SpellDescription$ CARDNAME deals 6 damage to each of up to six targets.
Oracle:[+1]: Chandra, the Firebrand deals 1 damage to any target.\n[−2]: When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.\n[−6]: Chandra, the Firebrand deals 6 damage to each of up to six targets.
diff --git a/forge-gui/res/cardsfolder/c/chandras_regulator.txt b/forge-gui/res/cardsfolder/c/chandras_regulator.txt
index 02515b748c4..e6fedd30b00 100644
--- a/forge-gui/res/cardsfolder/c/chandras_regulator.txt
+++ b/forge-gui/res/cardsfolder/c/chandras_regulator.txt
@@ -2,7 +2,7 @@ Name:Chandra's Regulator
ManaCost:1 R
Types:Legendary Artifact
T:Mode$ AbilityCast | ValidCard$ Planeswalker.Chandra | ValidActivatingPlayer$ You | ValidSA$ Activated.Loyalty | TriggerZones$ Battlefield | Execute$ TrigCopyAbility | TriggerDescription$ Whenever you activate a loyalty ability of a Chandra planeswalker, you may pay {1}. If you do, copy that ability. You may choose new targets for the copy.
-SVar:TrigCopyAbility:AB$ CopySpellAbility | Cost$ 1 | Defined$ TriggeredSpellAbility
+SVar:TrigCopyAbility:AB$ CopySpellAbility | Cost$ 1 | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
A:AB$ Draw | Cost$ 1 T Discard<1/Mountain;Card.Red/Mountain card or a red card> | NumCards$ 1 | SpellDescription$ Draw a card.
SVar:AIPreference:SacCost$Card.Mountain,Card.Red
DeckNeeds:Type$Chandra
diff --git a/forge-gui/res/cardsfolder/c/cloven_casting.txt b/forge-gui/res/cardsfolder/c/cloven_casting.txt
index ea70f2dfb54..5cca89f3cc2 100644
--- a/forge-gui/res/cardsfolder/c/cloven_casting.txt
+++ b/forge-gui/res/cardsfolder/c/cloven_casting.txt
@@ -2,7 +2,6 @@ Name:Cloven Casting
ManaCost:5 U R
Types:Enchantment
T:Mode$ SpellCast | ValidCard$ Instant.MultiColor,Sorcery.MultiColor | ValidActivatingPlayer$ You | Execute$ TrigCopy | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast a multicolored instant or sorcery spell, you may pay {1}. If you do, copy that spell. You may choose new targets for the copy.
-SVar:TrigCopy:AB$ CopySpellAbility | Cost$ 1 | Defined$ TriggeredSpellAbility
+SVar:TrigCopy:AB$ CopySpellAbility | Cost$ 1 | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
AI:RemoveDeck:Random
-SVar:Picture:http://www.wizards.com/global/images/magic/general/cloven_casting.jpg
Oracle:Whenever you cast a multicolored instant or sorcery spell, you may pay {1}. If you do, copy that spell. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/c/curse_of_echoes.txt b/forge-gui/res/cardsfolder/c/curse_of_echoes.txt
index f88f4c50cbc..2b1b01ddba7 100644
--- a/forge-gui/res/cardsfolder/c/curse_of_echoes.txt
+++ b/forge-gui/res/cardsfolder/c/curse_of_echoes.txt
@@ -4,8 +4,8 @@ Types:Enchantment Aura Curse
K:Enchant player
A:SP$ Attach | Cost$ 4 U | ValidTgts$ Player | AILogic$ Curse
T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ Player.EnchantedBy | Execute$ TrigCopy | TriggerZones$ Battlefield | OptionalDecider$ TriggeredCardOpponent | TriggerDescription$ Whenever enchanted player casts an instant or sorcery spell, each other player may copy that spell and may choose new targets for the copy they control.
-SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Controller$ TriggeredCardOpponent
+# TODO each player should copy it for multiplayer
+SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Controller$ TriggeredCardOpponent | MayChooseTarget$ True
AI:RemoveDeck:All
SVar:RemMultiplayer:True
-SVar:Picture:http://www.wizards.com/global/images/magic/general/curse_of_echoes.jpg
Oracle:Enchant player\nWhenever enchanted player casts an instant or sorcery spell, each other player may copy that spell and may choose new targets for the copy they control.
diff --git a/forge-gui/res/cardsfolder/d/double_stroke.txt b/forge-gui/res/cardsfolder/d/double_stroke.txt
index 5c45f500529..c6a464343c2 100644
--- a/forge-gui/res/cardsfolder/d/double_stroke.txt
+++ b/forge-gui/res/cardsfolder/d/double_stroke.txt
@@ -3,6 +3,6 @@ ManaCost:no cost
Types:Conspiracy
K:Hidden agenda
T:Mode$ SpellCast | ValidCard$ Instant.NamedCard,Sorcery.NamedCard | ValidActivatingPlayer$ You | Execute$ TrigCopySpell | TriggerZones$ Command | OptionalDecider$ You | TriggerDescription$ Whenever you cast an instant or sorcery spell with the chosen name, you may copy it. You may choose new targets for the copy.
-SVar:TrigCopySpell:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ 1
+SVar:TrigCopySpell:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ 1 | MayChooseTarget$ True
SVar:AgendaLogic:MostProminentSpellInComputerDeck
Oracle:Hidden agenda (Start the game with this conspiracy face down in the command zone and secretly name a card. You may turn this conspiracy face up any time and reveal the chosen name.)\nWhenever you cast an instant or sorcery spell with the chosen name, you may copy it. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/d/double_vision.txt b/forge-gui/res/cardsfolder/d/double_vision.txt
index e4a079ee471..c1f40d94dd1 100644
--- a/forge-gui/res/cardsfolder/d/double_vision.txt
+++ b/forge-gui/res/cardsfolder/d/double_vision.txt
@@ -2,6 +2,6 @@ Name:Double Vision
ManaCost:3 R R
Types:Enchantment
T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | ActivatorThisTurnCast$ EQ1 | NoResolvingCheck$ True | Execute$ TrigCopy | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast your first instant or sorcery spell each turn, copy that spell. You may choose new targets for the copy.
-SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | AILogic$ Always
+SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | AILogic$ Always | MayChooseTarget$ True
DeckHints:Type$Instant|Sorcery
Oracle:Whenever you cast your first instant or sorcery spell each turn, copy that spell. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/d/doublecast.txt b/forge-gui/res/cardsfolder/d/doublecast.txt
index a985e86df03..ba6ffc6a365 100644
--- a/forge-gui/res/cardsfolder/d/doublecast.txt
+++ b/forge-gui/res/cardsfolder/d/doublecast.txt
@@ -1,9 +1,7 @@
Name:Doublecast
ManaCost:R R
Types:Sorcery
-A:SP$ Effect | Cost$ R R | AILogic$ SpellCopy | Name$ Doublecast Effect | Triggers$ EffTModeSpellCast | SVars$ EffTrigCopy,EffDBCleanup | SpellDescription$ When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.
-SVar:EffTModeSpellCast:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | OneOff$ True | Execute$ EffTrigCopy | TriggerZones$ Command | TriggerDescription$ When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.
-SVar:EffTrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | SubAbility$ EffDBCleanup
-SVar:EffDBCleanup:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
+A:SP$ DelayedTrigger | Cost$ R R | AILogic$ SpellCopy | Execute$ EffTrigCopy | ThisTurn$ True | Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | SpellDescription$ When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.
+SVar:EffTrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
SVar:AIPriorityModifier:9
Oracle:When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for that copy.
diff --git a/forge-gui/res/cardsfolder/d/dual_casting.txt b/forge-gui/res/cardsfolder/d/dual_casting.txt
index bf905034d4e..f1584a35835 100644
--- a/forge-gui/res/cardsfolder/d/dual_casting.txt
+++ b/forge-gui/res/cardsfolder/d/dual_casting.txt
@@ -4,6 +4,6 @@ Types:Enchantment Aura
K:Enchant creature
A:SP$ Attach | Cost$ 1 R | ValidTgts$ Creature | AILogic$ Pump
S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddAbility$ ForkStick | Description$ Enchanted creature has "{R}, {T}: Copy target instant or sorcery spell you control. You may choose new targets for the copy."
-SVar:ForkStick:AB$ CopySpellAbility | Cost$ R T | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | SpellDescription$ Copy target instant or sorcery spell you control. You may choose new targets for the copy.
+SVar:ForkStick:AB$ CopySpellAbility | Cost$ R T | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell you control. You may choose new targets for the copy.
SVar:Picture:http://www.wizards.com/global/images/magic/general/dual_casting.jpg
Oracle:Enchant creature\nEnchanted creature has "{R}, {T}: Copy target instant or sorcery spell you control. You may choose new targets for the copy."
diff --git a/forge-gui/res/cardsfolder/d/dualcaster_mage.txt b/forge-gui/res/cardsfolder/d/dualcaster_mage.txt
index f303c17ffdb..7e2c7ced8f5 100644
--- a/forge-gui/res/cardsfolder/d/dualcaster_mage.txt
+++ b/forge-gui/res/cardsfolder/d/dualcaster_mage.txt
@@ -4,7 +4,6 @@ Types:Creature Human Wizard
PT:2/2
K:Flash
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigCopy | TriggerDescription$ When CARDNAME enters the battlefield, copy target instant or sorcery spell. You may choose new targets for that copy.
-SVar:TrigCopy:DB$ CopySpellAbility | ValidTgts$ Instant,Sorcery | TargetType$ Spell
+SVar:TrigCopy:DB$ CopySpellAbility | ValidTgts$ Instant,Sorcery | TargetType$ Spell | MayChooseTarget$ True
AI:RemoveDeck:All
-SVar:Picture:http://www.wizards.com/global/images/magic/general/dualcaster_mage.jpg
Oracle:Flash\nWhen Dualcaster Mage enters the battlefield, copy target instant or sorcery spell. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/e/echo_mage.txt b/forge-gui/res/cardsfolder/e/echo_mage.txt
index 755a94da0ba..a0ab3d1be7b 100644
--- a/forge-gui/res/cardsfolder/e/echo_mage.txt
+++ b/forge-gui/res/cardsfolder/e/echo_mage.txt
@@ -4,11 +4,8 @@ Types:Creature Human Wizard
PT:2/3
K:Level up:1 U
SVar:maxLevel:4
-S:Mode$ Continuous | Affected$ Card.Self | SetPower$ 2 | SetToughness$ 4 | AddAbility$ CopyOnce | CheckSVar$ X | SVarCompare$ EQ1 | Description$ LEVEL 2-3 2/4 CARDNAME gets U U,tap: Copy target instant or sorcery spell. You may choose new targets for the copy.
-S:Mode$ Continuous | Affected$ Card.Self | SetPower$ 2 | SetToughness$ 5 | AddAbility$ CopyTwice | CheckSVar$ Y | SVarCompare$ EQ1 | Description$ LEVEL 4+ 2/5 CARDNAME gets U U,tap:Copy target instant or sorcery spell twice. You may choose new targets for the copies.
-SVar:CopyOnce:AB$CopySpellAbility | Cost$ U U T | ValidTgts$ Instant,Sorcery | AILogic$ OnceIfViable | SpellDescription$ Copy target instant or sorcery spell. You may choose new targets for the copy.
-SVar:CopyTwice:AB$CopySpellAbility | Cost$ U U T | ValidTgts$ Instant,Sorcery | Amount$ 2 | AILogic$ OnceIfViable | SpellDescription$ Copy target instant or sorcery spell twice. You may choose new targets for the copies.
-SVar:X:Count$Valid Card.Self+counters_GE2_LEVEL+counters_LT4_LEVEL
-SVar:Y:Count$Valid Card.Self+counters_GE4_LEVEL
-SVar:Picture:http://www.wizards.com/global/images/magic/general/echo_mage.jpg
+S:Mode$ Continuous | Affected$ Card.Self | SetPower$ 2 | SetToughness$ 4 | AddAbility$ CopyOnce | IsPresent$ Card.Self+counters_GE2_LEVEL+counters_LT4_LEVEL | Description$ LEVEL 2-3 2/4 CARDNAME gets U U,tap: Copy target instant or sorcery spell. You may choose new targets for the copy.
+S:Mode$ Continuous | Affected$ Card.Self | SetPower$ 2 | SetToughness$ 5 | AddAbility$ CopyTwice | IsPresent$ Card.Self+counters_GE4_LEVEL | Description$ LEVEL 4+ 2/5 CARDNAME gets U U,tap:Copy target instant or sorcery spell twice. You may choose new targets for the copies.
+SVar:CopyOnce:AB$ CopySpellAbility | Cost$ U U T | ValidTgts$ Instant,Sorcery | AILogic$ OnceIfViable | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell. You may choose new targets for the copy.
+SVar:CopyTwice:AB$ CopySpellAbility | Cost$ U U T | ValidTgts$ Instant,Sorcery | Amount$ 2 | AILogic$ OnceIfViable | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell twice. You may choose new targets for the copies.
Oracle:Level up {1}{U} ({1}{U}: Put a level counter on this. Level up only as a sorcery.)\nLEVEL 2-3\n2/4\n{U}{U}, {T}: Copy target instant or sorcery spell. You may choose new targets for the copy.\nLEVEL 4+\n2/5\n{U}{U}, {T}: Copy target instant or sorcery spell twice. You may choose new targets for the copies.
diff --git a/forge-gui/res/cardsfolder/e/echo_storm.txt b/forge-gui/res/cardsfolder/e/echo_storm.txt
index 24fb9ef5449..fbc001e8eae 100644
--- a/forge-gui/res/cardsfolder/e/echo_storm.txt
+++ b/forge-gui/res/cardsfolder/e/echo_storm.txt
@@ -2,7 +2,7 @@ Name:Echo Storm
ManaCost:3 U U
Types:Sorcery
T:Mode$ SpellCast | ValidCard$ Card.Self | Execute$ TrigCopy | TriggerDescription$ When you cast this spell, copy it for each time you've cast your commander from the command zone this game.
-SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ X | References$ X
+SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ X | References$ X | MayChooseTarget$ True
SVar:X:Count$TotalCommanderCastFromCommandZone
A:SP$ CopyPermanent | Cost$ 3 U U | ValidTgts$ Artifact | TgtPrompt$ Select target artifact. | SpellDescription$ Create a token that's a copy of target artifact.
DeckHas:Ability$Token
diff --git a/forge-gui/res/cardsfolder/e/echoing_boon.txt b/forge-gui/res/cardsfolder/e/echoing_boon.txt
index 9e7c9a7a83a..0f726404359 100644
--- a/forge-gui/res/cardsfolder/e/echoing_boon.txt
+++ b/forge-gui/res/cardsfolder/e/echoing_boon.txt
@@ -3,7 +3,6 @@ ManaCost:no cost
Types:Conspiracy
K:Hidden agenda
T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | TriggerZones$ Command | TargetsValid$ Card.NamedCard+YouCtrl | Execute$ TrigCopySpell | OptionalDecider$ You | TriggerDescription$ Whenever you cast an instant or sorcery spell, if it targets a creature you control with the chosen name, you may copy that spell and may choose new targets for the copy.
-SVar:TrigCopySpell:DB$CopySpellAbility | Defined$ TriggeredSpellAbility
+SVar:TrigCopySpell:DB$CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
SVar:AgendaLogic:BestCreatureInComputerDeck
-SVar:Picture:http://www.wizards.com/global/images/magic/general/echoing_boon.jpg
Oracle:Hidden agenda (Start the game with this conspiracy face down in the command zone and secretly name a card. You may turn this conspiracy face up any time and reveal the chosen name.)\nWhenever you cast an instant or sorcery spell, if it targets a creature you control with the chosen name, you may copy that spell and may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/e/empyrial_storm.txt b/forge-gui/res/cardsfolder/e/empyrial_storm.txt
index 7925680042f..4fb4817b905 100644
--- a/forge-gui/res/cardsfolder/e/empyrial_storm.txt
+++ b/forge-gui/res/cardsfolder/e/empyrial_storm.txt
@@ -2,7 +2,7 @@ Name:Empyrial Storm
ManaCost:4 W W
Types:Sorcery
T:Mode$ SpellCast | ValidCard$ Card.Self | Execute$ TrigCopy | TriggerDescription$ When you cast this spell, copy it for each time you've cast your commander from the command zone this game.
-SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ X | References$ X
+SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ X | References$ X | MayChooseTarget$ True
SVar:X:Count$TotalCommanderCastFromCommandZone
A:SP$ Token | Cost$ 4 W W | TokenAmount$ 1 | TokenScript$ w_4_4_angel_flying | TokenOwner$ You | LegacyImage$ w 4 4 angel flying c18 | SpellDescription$ Create a 4/4 white Angel creature token with flying.
DeckHas:Ability$Token
diff --git a/forge-gui/res/cardsfolder/e/expansion_explosion.txt b/forge-gui/res/cardsfolder/e/expansion_explosion.txt
index bb7bbd290ee..f071098855c 100644
--- a/forge-gui/res/cardsfolder/e/expansion_explosion.txt
+++ b/forge-gui/res/cardsfolder/e/expansion_explosion.txt
@@ -2,7 +2,7 @@ Name:Expansion
ManaCost:U/R U/R
Types:Instant
AlternateMode: Split
-A:SP$ CopySpellAbility | Cost$ U/R U/R | ValidTgts$ Card.Instant+cmcLE4,Card.Sorcery+cmcLE4 | TargetType$ Spell | SpellDescription$ Copy target instant or sorcery spell with converted mana cost 4 or less. You may choose new targets for the copy.
+A:SP$ CopySpellAbility | Cost$ U/R U/R | ValidTgts$ Card.Instant+cmcLE4,Card.Sorcery+cmcLE4 | TargetType$ Spell | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell with converted mana cost 4 or less. You may choose new targets for the copy.
Oracle:Copy target instant or sorcery spell with converted mana cost 4 or less. You may choose new targets for the copy.
ALTERNATE
diff --git a/forge-gui/res/cardsfolder/f/finale_of_promise.txt b/forge-gui/res/cardsfolder/f/finale_of_promise.txt
index 96f12977f1b..2f4fa83bd4e 100644
--- a/forge-gui/res/cardsfolder/f/finale_of_promise.txt
+++ b/forge-gui/res/cardsfolder/f/finale_of_promise.txt
@@ -5,6 +5,6 @@ A:SP$ Pump | Cost$ X R R | ValidTgts$ Instant.YouOwn+cmcLEX | TgtZone$ Graveyard
SVar:DBPump:DB$ Pump | ValidTgts$ Sorcery.YouOwn+cmcLEX | TgtZone$ Graveyard | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Select target sorcery card in your graveyard with converted mana cost X or less | RememberObjects$ Targeted | SubAbility$ DBPlay | References$ X | StackDescription$ None
SVar:DBPlay:DB$ Play | Valid$ Card.IsRemembered | ValidZone$ Graveyard | Controller$ You | CopyCard$ True | CopyOnce$ True | WithoutManaCost$ True | Optional$ True | Amount$ All | SubAbility$ DBRepeat
SVar:DBRepeat:DB$ RepeatEach | DefinedCards$ Remembered | ClearRemembered$ True | ChooseOrder$ True | RepeatSubAbility$ DBCopy | References$ X | ConditionCheckSVar$ X | ConditionSVarCompare$ GE10
-SVar:DBCopy:DB$ CopySpellAbility | Amount$ 2 | Defined$ Remembered
+SVar:DBCopy:DB$ CopySpellAbility | Amount$ 2 | Defined$ Remembered | MayChooseTarget$ True
SVar:X:Count$xPaid
-Oracle:You may cast up to one target instant card and/or sorcery card from your graveyard each with converted mana cost X or less without paying their mana costs. If a card cast this way would be put into your graveyard this turn, exile it instead. If X is 10 or more, copy each of those spells twice. You may choose new targets for the copies.
\ No newline at end of file
+Oracle:You may cast up to one target instant card and/or sorcery card from your graveyard each with converted mana cost X or less without paying their mana costs. If a card cast this way would be put into your graveyard this turn, exile it instead. If X is 10 or more, copy each of those spells twice. You may choose new targets for the copies.
diff --git a/forge-gui/res/cardsfolder/f/fork.txt b/forge-gui/res/cardsfolder/f/fork.txt
index 84dd0f13fc4..ee58faa4933 100644
--- a/forge-gui/res/cardsfolder/f/fork.txt
+++ b/forge-gui/res/cardsfolder/f/fork.txt
@@ -1,6 +1,5 @@
Name:Fork
ManaCost:R R
Types:Instant
-A:SP$ CopySpellAbility | Cost$ R R | ValidTgts$ Instant,Sorcery | TargetType$ Spell | CopyIsColor$ Red | OverwriteColors$ True | SpellDescription$ Copy target instant or sorcery spell, except that the copy is red. You may choose new targets for the copy.
-SVar:Picture:http://www.wizards.com/global/images/magic/general/fork.jpg
+A:SP$ CopySpellAbility | Cost$ R R | ValidTgts$ Instant,Sorcery | TargetType$ Spell | CopyIsColor$ Red | OverwriteColors$ True | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell, except that the copy is red. You may choose new targets for the copy.
Oracle:Copy target instant or sorcery spell, except that the copy is red. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/f/fury_storm.txt b/forge-gui/res/cardsfolder/f/fury_storm.txt
index 6895b278dd6..19c481c8bbb 100644
--- a/forge-gui/res/cardsfolder/f/fury_storm.txt
+++ b/forge-gui/res/cardsfolder/f/fury_storm.txt
@@ -2,7 +2,7 @@ Name:Fury Storm
ManaCost:2 R R
Types:Instant
T:Mode$ SpellCast | ValidCard$ Card.Self | Execute$ TrigCopy | TriggerDescription$ When you cast this spell, copy it for each time you've cast your commander from the command zone this game.
-SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ X | References$ X
+SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ X | References$ X | MayChooseTarget$ True
SVar:X:Count$TotalCommanderCastFromCommandZone
-A:SP$ CopySpellAbility | Cost$ 2 R R | ValidTgts$ Instant,Sorcery | TargetType$ Spell | SpellDescription$ Copy target instant or sorcery spell. You may choose new targets for the copy.
+A:SP$ CopySpellAbility | Cost$ 2 R R | ValidTgts$ Instant,Sorcery | TargetType$ Spell | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell. You may choose new targets for the copy.
Oracle:When you cast this spell, copy it for each time you've cast your commander from the command zone this game. You may choose new targets for the copies.\nCopy target instant or sorcery spell. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/g/geistblast.txt b/forge-gui/res/cardsfolder/g/geistblast.txt
index 4be13b50adf..aaad303346b 100644
--- a/forge-gui/res/cardsfolder/g/geistblast.txt
+++ b/forge-gui/res/cardsfolder/g/geistblast.txt
@@ -2,7 +2,6 @@ Name:Geistblast
ManaCost:2 R
Types:Instant
A:SP$ DealDamage | Cost$ 2 R | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ 2 | SpellDescription$ CARDNAME deals 2 damage to any target.
-A:AB$ CopySpellAbility | Cost$ 2 U ExileFromGrave<1/CARDNAME> | ActivationZone$ Graveyard | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | TargetType$ Spell | SpellDescription$ Copy target instant or sorcery spell you control. You may choose new targets for the copy.
+A:AB$ CopySpellAbility | Cost$ 2 U ExileFromGrave<1/CARDNAME> | ActivationZone$ Graveyard | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | TargetType$ Spell | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell you control. You may choose new targets for the copy.
SVar:AIPreference:ExileFromGraveCost$Card.Self
-SVar:Picture:http://www.wizards.com/global/images/magic/general/geistblast.jpg
Oracle:Geistblast deals 2 damage to any target.\n{2}{U}, Exile Geistblast from your graveyard: Copy target instant or sorcery spell you control. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/g/genesis_storm.txt b/forge-gui/res/cardsfolder/g/genesis_storm.txt
index ed19640f1f0..6a004f82421 100644
--- a/forge-gui/res/cardsfolder/g/genesis_storm.txt
+++ b/forge-gui/res/cardsfolder/g/genesis_storm.txt
@@ -2,7 +2,7 @@ Name:Genesis Storm
ManaCost:4 G G
Types:Sorcery
T:Mode$ SpellCast | ValidCard$ Card.Self | Execute$ TrigCopy | TriggerDescription$ When you cast this spell, copy it for each time you've cast your commander from the command zone this game.
-SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ X | References$ X
+SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ X | References$ X | MayChooseTarget$ True
SVar:X:Count$TotalCommanderCastFromCommandZone
A:SP$ DigUntil | Cost$ 4 G G | Valid$ Permanent.nonland | ValidDescription$ nonland permanent | FoundDestination$ Battlefield | OptionalFoundMove$ True | RevealedDestination$ Library | RevealedLibraryPosition$ -1 | RevealRandomOrder$ True | SpellDescription$ Reveal cards from the top of your library until you reveal a nonland permanent card. You may put that card onto the battlefield. Then put all cards revealed this way that weren't put onto the battlefield on the bottom of your library in a random order.
Oracle:When you cast this spell, copy it for each time you've cast your commander from the command zone this game. You may choose new targets for the copies.\nReveal cards from the top of your library until you reveal a nonland permanent card. You may put that card onto the battlefield. Then put all cards revealed this way that weren't put onto the battlefield on the bottom of your library in a random order.
diff --git a/forge-gui/res/cardsfolder/h/hive_mind.txt b/forge-gui/res/cardsfolder/h/hive_mind.txt
index 2cb798a8cf2..122f08a861b 100644
--- a/forge-gui/res/cardsfolder/h/hive_mind.txt
+++ b/forge-gui/res/cardsfolder/h/hive_mind.txt
@@ -2,8 +2,7 @@ Name:Hive Mind
ManaCost:5 U
Types:Enchantment
T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ Player | Execute$ TrigCopy | TriggerZones$ Battlefield | TriggerDescription$ Whenever a player casts an instant or sorcery spell, each other player copies that spell. Each of those players may choose new targets for their copy.
-SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Controller$ TriggeredCardOpponent
+SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Controller$ TriggeredCardOpponent | MayChooseTarget$ True
AI:RemoveDeck:Random
SVar:RemMultiplayer:True
-SVar:Picture:http://www.wizards.com/global/images/magic/general/hive_mind.jpg
Oracle:Whenever a player casts an instant or sorcery spell, each other player copies that spell. Each of those players may choose new targets for their copy.
diff --git a/forge-gui/res/cardsfolder/h/howl_of_the_horde.txt b/forge-gui/res/cardsfolder/h/howl_of_the_horde.txt
index 7ab1185033a..3e5470b7009 100644
--- a/forge-gui/res/cardsfolder/h/howl_of_the_horde.txt
+++ b/forge-gui/res/cardsfolder/h/howl_of_the_horde.txt
@@ -1,11 +1,9 @@
Name:Howl of the Horde
ManaCost:2 R
Types:Sorcery
-A:SP$ Effect | Cost$ 2 R | AILogic$ SpellCopy | Name$ Howl of the Horde Effect 1 | Triggers$ TrigCopy | SVars$ TrigCopyMain,DBCleanup | SubAbility$ DBEffect | SpellDescription$ When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy. Raid — If you attacked this turn, when you cast your next instant or sorcery spell this turn, copy that spell an additional time. You may choose new targets for the copy.
-SVar:DBEffect:DB$ Effect | Name$ Howl of the Horde Effect 2 | Triggers$ TrigCopy | SVars$ TrigCopyMain,DBCleanup | ConditionCheckSVar$ RaidTest | ConditionSVarCompare$ GE1 | References$ RaidTest
+A:SP$ DelayedTrigger | Cost$ 2 R | AILogic$ SpellCopy | Execute$ EffTrigCopy | ThisTurn$ True | Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | | SubAbility$ DBEffect | SpellDescription$ When you cast your next instant or sorcery spell this turn, copy that spell.
+SVar:DBEffect:DB$ DelayedTrigger | AILogic$ SpellCopy | Execute$ EffTrigCopy | ThisTurn$ True | Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | ConditionCheckSVar$ RaidTest | ConditionSVarCompare$ GE1 | References$ RaidTest | SpellDescription$ Raid — If you attacked this turn, when you cast your next instant or sorcery spell this turn, copy that spell an additional time. You may choose new targets for the copy.
SVar:RaidTest:Count$AttackersDeclared
-SVar:TrigCopy:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | OneOff$ True | Execute$ TrigCopyMain | TriggerZones$ Command | TriggerDescription$ When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.
-SVar:TrigCopyMain:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | SubAbility$ DBCleanup
-SVar:DBCleanup:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
+SVar:EffTrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
SVar:AIPriorityModifier:9
Oracle:When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.\nRaid — If you attacked this turn, when you cast your next instant or sorcery spell this turn, copy that spell an additional time. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/i/illusionists_bracers.txt b/forge-gui/res/cardsfolder/i/illusionists_bracers.txt
index 557c5f2d2ef..7be98b5b050 100644
--- a/forge-gui/res/cardsfolder/i/illusionists_bracers.txt
+++ b/forge-gui/res/cardsfolder/i/illusionists_bracers.txt
@@ -3,6 +3,5 @@ ManaCost:2
Types:Artifact Equipment
K:Equip:3
T:Mode$ AbilityCast | ValidCard$ Creature.EquippedBy | TriggerZones$ Battlefield | Execute$ TrigCopyAbility | OptionalDecider$ You | TriggerDescription$ Whenever an ability of equipped creature is activated, if it isn't a mana ability, copy that ability. You may choose new targets for the copy.
-SVar:TrigCopyAbility:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility
-SVar:Picture:http://www.wizards.com/global/images/magic/general/illusionists_bracers.jpg
+SVar:TrigCopyAbility:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
Oracle:Whenever an ability of equipped creature is activated, if it isn't a mana ability, copy that ability. You may choose new targets for the copy.\nEquip {3}
diff --git a/forge-gui/res/cardsfolder/i/increasing_vengeance.txt b/forge-gui/res/cardsfolder/i/increasing_vengeance.txt
index 1c864b599af..0b1ff154886 100644
--- a/forge-gui/res/cardsfolder/i/increasing_vengeance.txt
+++ b/forge-gui/res/cardsfolder/i/increasing_vengeance.txt
@@ -2,8 +2,6 @@ Name:Increasing Vengeance
ManaCost:R R
Types:Instant
K:Flashback:3 R R
-A:SP$ CopySpellAbility | Cost$ R R | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | TargetType$ Spell | SubAbility$ DBCopy2 | SpellDescription$ Copy target instant or sorcery spell you control. If this spell was cast from a graveyard, copy that spell twice instead. You may choose new targets for the copies.
-SVar:DBCopy2:DB$ CopySpellAbility | Defined$ Targeted | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | References$ X | AILogic$ Always
-SVar:X:Count$wasCastFromGraveyard.1.0
-SVar:Picture:http://www.wizards.com/global/images/magic/general/increasing_vengeance.jpg
+A:SP$ CopySpellAbility | Cost$ R R | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | TargetType$ Spell | Amount$ X | References$ X | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell you control. If this spell was cast from a graveyard, copy that spell twice instead. You may choose new targets for the copies.
+SVar:X:Count$wasCastFromGraveyard.2.1
Oracle:Copy target instant or sorcery spell you control. If this spell was cast from a graveyard, copy that spell twice instead. You may choose new targets for the copies.\nFlashback {3}{R}{R} (You may cast this card from your graveyard for its flashback cost. Then exile it.)
diff --git a/forge-gui/res/cardsfolder/i/insidious_will.txt b/forge-gui/res/cardsfolder/i/insidious_will.txt
index 31f34d6e891..f8b472cfc1b 100644
--- a/forge-gui/res/cardsfolder/i/insidious_will.txt
+++ b/forge-gui/res/cardsfolder/i/insidious_will.txt
@@ -4,6 +4,5 @@ Types:Instant
A:SP$ Charm | Cost$ 2 U U | Choices$ DBCounter,DBChangeTargets,DBCopySpellAbility | Defined$ You
SVar:DBCounter:DB$ Counter | TargetType$ Spell | ValidTgts$ Card | TgtPrompt$ Counter target spell | SpellDescription$ Counter target spell.
SVar:DBChangeTargets:DB$ ChangeTargets | TargetType$ Spell | Optional$ True | ValidTgts$ Card | SpellDescription$ You may choose new targets for target spell.
-SVar:DBCopySpellAbility:DB$ CopySpellAbility | ValidTgts$ Instant,Sorcery | TargetType$ Spell | SpellDescription$ Copy target instant or sorcery spell. You may choose new targets for the copy.
-SVar:Picture:http://www.wizards.com/global/images/magic/general/insidious_will.jpg
+SVar:DBCopySpellAbility:DB$ CopySpellAbility | ValidTgts$ Instant,Sorcery | TargetType$ Spell | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell. You may choose new targets for the copy.
Oracle:Choose one —\n• Counter target spell.\n• You may choose new targets for target spell.\n• Copy target instant or sorcery spell. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/i/izzet_guildmage.txt b/forge-gui/res/cardsfolder/i/izzet_guildmage.txt
index 39c32abfe50..648c2d955b7 100644
--- a/forge-gui/res/cardsfolder/i/izzet_guildmage.txt
+++ b/forge-gui/res/cardsfolder/i/izzet_guildmage.txt
@@ -2,7 +2,6 @@ Name:Izzet Guildmage
ManaCost:UR UR
Types:Creature Human Wizard
PT:2/2
-A:AB$ CopySpellAbility | Cost$ 2 U | ValidTgts$ Instant.YouCtrl+cmcLE2 | TargetType$ Spell | AILogic$ OnceIfViable | SpellDescription$ Copy target instant spell you control with converted mana cost 2 or less. You may choose new targets for the copy.
-A:AB$ CopySpellAbility | Cost$ 2 R | ValidTgts$ Sorcery.YouCtrl+cmcLE2 | TargetType$ Spell | AILogic$ OnceIfViable | SpellDescription$ Copy target sorcery spell you control with converted mana cost 2 or less. You may choose new targets for the copy.
-SVar:Picture:http://www.wizards.com/global/images/magic/general/izzet_guildmage.jpg
+A:AB$ CopySpellAbility | Cost$ 2 U | ValidTgts$ Instant.YouCtrl+cmcLE2 | TargetType$ Spell | AILogic$ OnceIfViable | MayChooseTarget$ True | SpellDescription$ Copy target instant spell you control with converted mana cost 2 or less. You may choose new targets for the copy.
+A:AB$ CopySpellAbility | Cost$ 2 R | ValidTgts$ Sorcery.YouCtrl+cmcLE2 | TargetType$ Spell | AILogic$ OnceIfViable | MayChooseTarget$ True | SpellDescription$ Copy target sorcery spell you control with converted mana cost 2 or less. You may choose new targets for the copy.
Oracle:{2}{U}: Copy target instant spell you control with converted mana cost 2 or less. You may choose new targets for the copy.\n{2}{R}: Copy target sorcery spell you control with converted mana cost 2 or less. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/i/izzet_steam_maze.txt b/forge-gui/res/cardsfolder/i/izzet_steam_maze.txt
index 98684d6922e..85e00e4bbef 100644
--- a/forge-gui/res/cardsfolder/i/izzet_steam_maze.txt
+++ b/forge-gui/res/cardsfolder/i/izzet_steam_maze.txt
@@ -2,10 +2,9 @@ Name:Izzet Steam Maze
ManaCost:no cost
Types:Plane Ravnica
T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ Player | Execute$ TrigCopy | TriggerZones$ Command | TriggerDescription$ Whenever a player casts an instant or sorcery spell, that player copies it. The player may choose new targets for the copy.
-SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Controller$ TriggeredActivator
+SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Controller$ TriggeredActivator | MayChooseTarget$ True
T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll {CHAOS}, instant and sorcery spells you cast this turn cost {3} less to cast.
SVar:RolledChaos:DB$ Effect | StaticAbilities$ ReduceSPcost
SVar:ReduceSPcost:Mode$ ReduceCost | EffectZone$ Command | ValidCard$ Instant,Sorcery | Type$ Spell | Activator$ You | Amount$ 3 | Description$ Instant and sorcery spells you cast this turn cost 3 less to cast.
-SVar:Picture:http://www.wizards.com/global/images/magic/general/izzet_steam_maze.jpg
SVar:AIRollPlanarDieParams:Mode$ Always | RollInMain1$ True
Oracle:Whenever a player casts an instant or sorcery spell, that player copies it. The player may choose new targets for the copy.\nWhenever you roll {CHAOS}, instant and sorcery spells you cast this turn cost {3} less to cast.
diff --git a/forge-gui/res/cardsfolder/k/kalamax_the_stormsire.txt b/forge-gui/res/cardsfolder/k/kalamax_the_stormsire.txt
index 05d6f1d4fc0..29a8ba0fa4b 100755
--- a/forge-gui/res/cardsfolder/k/kalamax_the_stormsire.txt
+++ b/forge-gui/res/cardsfolder/k/kalamax_the_stormsire.txt
@@ -3,7 +3,7 @@ ManaCost:1 G U R
Types:Legendary Creature Elemental Dinosaur
PT:4/4
T:Mode$ SpellCast | ValidCard$ Instant | ValidActivatingPlayer$ You | ActivatorThisTurnCast$ EQ1 | NoResolvingCheck$ True | Execute$ TrigCopy | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast your first instant spell each turn, if CARDNAME is tapped, copy that spell. You may choose new targets for the copy.
-SVar:TrigCopy:DB$ CopySpellAbility | ConditionPresent$ Card.Self+tapped | Defined$ TriggeredSpellAbility | AILogic$ Always
+SVar:TrigCopy:DB$ CopySpellAbility | ConditionPresent$ Card.Self+tapped | Defined$ TriggeredSpellAbility | AILogic$ Always | MayChooseTarget$ True
SVar:BuffedBy:Instant
T:Mode$ SpellCopy | ValidCard$ Instant | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever you copy an instant spell, put a +1/+1 counter on CARDNAME.
DeckHas:Ability$Counters
diff --git a/forge-gui/res/cardsfolder/k/kurkesh_onakke_ancient.txt b/forge-gui/res/cardsfolder/k/kurkesh_onakke_ancient.txt
index 1d1d7ad43e5..bd3dd5592d9 100644
--- a/forge-gui/res/cardsfolder/k/kurkesh_onakke_ancient.txt
+++ b/forge-gui/res/cardsfolder/k/kurkesh_onakke_ancient.txt
@@ -3,6 +3,5 @@ ManaCost:2 R R
Types:Legendary Creature Ogre Spirit
PT:4/3
T:Mode$ AbilityCast | ValidCard$ Artifact | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigCopyAbility | TriggerDescription$ Whenever you activate an ability of an artifact, if it isn't a mana ability, you may pay {R}. If you do, copy that ability. You may choose new targets for the copy.
-SVar:TrigCopyAbility:AB$ CopySpellAbility | Cost$ R | Defined$ TriggeredSpellAbility
-SVar:Picture:http://www.wizards.com/global/images/magic/general/kurkesh_onakke_ancient.jpg
+SVar:TrigCopyAbility:AB$ CopySpellAbility | Cost$ R | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
Oracle:Whenever you activate an ability of an artifact, if it isn't a mana ability, you may pay {R}. If you do, copy that ability. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/l/league_guildmage.txt b/forge-gui/res/cardsfolder/l/league_guildmage.txt
index d8b6669129b..d3db5ea95b6 100644
--- a/forge-gui/res/cardsfolder/l/league_guildmage.txt
+++ b/forge-gui/res/cardsfolder/l/league_guildmage.txt
@@ -3,7 +3,7 @@ ManaCost:U R
Types:Creature Human Wizard
PT:2/2
A:AB$ Draw | Cost$ 3 U T | NumCards$ 1 | SpellDescription$ Draw a card.
-A:AB$ CopySpellAbility | Cost$ X R T | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | TargetType$ Spell | AILogic$ OnceIfViable | SpellDescription$ Copy target instant or sorcery spell you control with converted mana cost X. You may choose new targets for the copy.
+A:AB$ CopySpellAbility | Cost$ X R T | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | TargetType$ Spell | AILogic$ OnceIfViable | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell you control with converted mana cost X. You may choose new targets for the copy.
SVar:X:Targeted$CardManaCost
DeckHints:Type$Instant|Sorcery
Oracle:{3}{U}, {T}: Draw a card.\n{X}{R}, {T}: Copy target instant or sorcery spell you control with converted mana cost X. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/l/lithoform_engine.txt b/forge-gui/res/cardsfolder/l/lithoform_engine.txt
new file mode 100644
index 00000000000..d7ef57a8755
--- /dev/null
+++ b/forge-gui/res/cardsfolder/l/lithoform_engine.txt
@@ -0,0 +1,8 @@
+Name:Lithoform Engine
+ManaCost:4
+Types:Legendary Artifact
+A:AB$ CopySpellAbility | Cost$ 2 T | TgtPrompt$ Select target activated or triggered ability you control | TargetType$ Activated.YouCtrl,Triggered.YouCtrl | ValidTgts$ Card | MayChooseTarget$ True | StackDescription$ SpellDescription | SpellDescription$ Copy target activated or triggered ability you control. You may choose new targets for the copy.
+A:AB$ CopySpellAbility | Cost$ 3 T | TgtPrompt$ Select target instant or sorcery spell you control | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | TargetType$ Spell | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell you control. You may choose new targets for the copy.
+A:AB$ CopySpellAbility | Cost$ 4 T | TgtPrompt$ Select target permanent spell you control | ValidTgts$ Permanent.YouCtrl | TargetType$ Spell | SpellDescription$ Copy target permanent spell you control. (The copy becomes a token.)
+Oracle:{2}, {T}: Copy target activated or triggered ability you control. You may choose new targets for the copy.\n{3}, {T}: Copy target instant or sorcery spell you control. You may choose new targets for the copy.\n{4}, {T}: Copy target permanent spell you control. (The copy becomes a token.)
+
diff --git a/forge-gui/res/cardsfolder/l/lucky_clover.txt b/forge-gui/res/cardsfolder/l/lucky_clover.txt
index c53cfbfc01e..cb74d740cec 100644
--- a/forge-gui/res/cardsfolder/l/lucky_clover.txt
+++ b/forge-gui/res/cardsfolder/l/lucky_clover.txt
@@ -2,6 +2,6 @@ Name:Lucky Clover
ManaCost:2
Types:Artifact
T:Mode$ SpellCast | ValidCard$ Instant.Adventure,Sorcery.Adventure | ValidActivatingPlayer$ You | Execute$ TrigCopySpell | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast an Adventure instant or sorcery spell, copy it. You may choose new targets for the copy.
-SVar:TrigCopySpell:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility
+SVar:TrigCopySpell:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
AI:RemoveDeck:Random
Oracle:Whenever you cast an Adventure instant or sorcery spell, copy it. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/l/lutri_the_spellchaser.txt b/forge-gui/res/cardsfolder/l/lutri_the_spellchaser.txt
index 7d6d3ea81e0..e6f8409a447 100644
--- a/forge-gui/res/cardsfolder/l/lutri_the_spellchaser.txt
+++ b/forge-gui/res/cardsfolder/l/lutri_the_spellchaser.txt
@@ -5,6 +5,6 @@ PT:3/2
K:Companion:Special:UniqueNames:Each nonland card in your starting deck has a different name.
K:Flash
T:Mode$ ChangesZone | ValidCard$ Card.Self+wasCast | Origin$ Any | Destination$ Battlefield | Execute$ TrigCopy | TriggerDescription$ When CARDNAME enters the battlefield, if you cast it, copy target instant or sorcery spell you control. You may choose new targets for the copy.
-SVar:TrigCopy:DB$ CopySpellAbility | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | TgtPrompt$ Select target instant or sorcery spell you control
+SVar:TrigCopy:DB$ CopySpellAbility | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | TgtPrompt$ Select target instant or sorcery spell you control | MayChooseTarget$ True
DeckHints:Type$Instant|Sorcery
Oracle:Companion — Each nonland card in your starting deck has a different name. (If this card is your chosen companion, you may cast it once from outside the game.)\nFlash\nWhen Lutri, the Spellchaser enters the battlefield, if you cast it, copy target instant or sorcery spell you control. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/m/malicious_affliction.txt b/forge-gui/res/cardsfolder/m/malicious_affliction.txt
index 392921f55b0..46c3f3108aa 100644
--- a/forge-gui/res/cardsfolder/m/malicious_affliction.txt
+++ b/forge-gui/res/cardsfolder/m/malicious_affliction.txt
@@ -3,7 +3,6 @@ ManaCost:B B
Types:Instant
A:SP$ Destroy | Cost$ B B | ValidTgts$ Creature.nonBlack | TgtPrompt$ Select target nonblack creature | SpellDescription$ Destroy target nonblack creature.
T:Mode$ SpellCast | ValidCard$ Card.Self | Execute$ TrigCopy | CheckSVar$ Morbid | SVarCompare$ GE1 | TriggerDescription$ Morbid — When you cast CARDNAME, if a creature died this turn, you may copy CARDNAME and may choose a new target for the copy.
-SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility
+SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
SVar:Morbid:Count$ThisTurnEntered_Graveyard_from_Battlefield_Creature
-SVar:Picture:http://www.wizards.com/global/images/magic/general/malicious_affliction.jpg
Oracle:Morbid — When you cast Malicious Affliction, if a creature died this turn, you may copy Malicious Affliction and may choose a new target for the copy.\nDestroy target nonblack creature.
diff --git a/forge-gui/res/cardsfolder/m/melek_izzet_paragon.txt b/forge-gui/res/cardsfolder/m/melek_izzet_paragon.txt
index d11a2faf11d..d8953117fc3 100644
--- a/forge-gui/res/cardsfolder/m/melek_izzet_paragon.txt
+++ b/forge-gui/res/cardsfolder/m/melek_izzet_paragon.txt
@@ -5,7 +5,7 @@ PT:2/4
S:Mode$ Continuous | Affected$ Card.TopLibrary+YouCtrl | AffectedZone$ Library | MayLookAt$ Player | Description$ Play with the top card of your library revealed.
S:Mode$ Continuous | Affected$ Instant.TopLibrary+YouCtrl,Sorcery.TopLibrary+YouCtrl | AffectedZone$ Library | EffectZone$ Battlefield | MayPlay$ True | Description$ You may cast the top card of your library if it's an instant or sorcery card.
T:Mode$ SpellCast | ValidCard$ Instant.wasCastFromLibrary,Sorcery.wasCastFromLibrary | ValidActivatingPlayer$ You | Execute$ TrigCopy | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast an instant or sorcery spell from your library, copy it. You may choose new targets for this copy.
-SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility
+SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
DeckNeeds:Type$Instant|Sorcery
SVar:Picture:http://www.wizards.com/global/images/magic/general/melek_izzet_paragon.jpg
Oracle:Play with the top card of your library revealed.\nYou may cast the top card of your library if it's an instant or sorcery card.\nWhenever you cast an instant or sorcery spell from your library, copy it. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/m/meletis_charlatan.txt b/forge-gui/res/cardsfolder/m/meletis_charlatan.txt
index debe3fbbc08..28a09b2d8dd 100644
--- a/forge-gui/res/cardsfolder/m/meletis_charlatan.txt
+++ b/forge-gui/res/cardsfolder/m/meletis_charlatan.txt
@@ -2,6 +2,5 @@ Name:Meletis Charlatan
ManaCost:2 U
Types:Creature Human Wizard
PT:2/3
-A:AB$ CopySpellAbility | Cost$ 2 U T | ValidTgts$ Instant,Sorcery | TargetType$ Spell | Controller$ TargetedController | AILogic$ OnceIfViable | AITgts$ OwnedOnly | SpellDescription$ The controller of target instant or sorcery spell copies it. That player may choose new targets for the copy.
-SVar:Picture:http://www.wizards.com/global/images/magic/general/meletis_charlatan.jpg
+A:AB$ CopySpellAbility | Cost$ 2 U T | ValidTgts$ Instant,Sorcery | TargetType$ Spell | Controller$ TargetedController | AILogic$ OnceIfViable | AITgts$ OwnedOnly | MayChooseTarget$ True | SpellDescription$ The controller of target instant or sorcery spell copies it. That player may choose new targets for the copy.
Oracle:{2}{U}, {T}: The controller of target instant or sorcery spell copies it. That player may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/m/mirari.txt b/forge-gui/res/cardsfolder/m/mirari.txt
index c1b674b58c3..ebff8dfd830 100644
--- a/forge-gui/res/cardsfolder/m/mirari.txt
+++ b/forge-gui/res/cardsfolder/m/mirari.txt
@@ -2,6 +2,5 @@ Name:Mirari
ManaCost:5
Types:Legendary Artifact
T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigCopy | TriggerDescription$ Whenever you cast an instant or sorcery spell, you may pay {3}. If you do, copy that spell. You may choose new targets for the copy.
-SVar:TrigCopy:AB$CopySpellAbility | Cost$ 3 | Defined$ TriggeredSpellAbility | AILogic$ AlwaysIfViable
-SVar:Picture:http://www.wizards.com/global/images/magic/general/mirari.jpg
+SVar:TrigCopy:AB$CopySpellAbility | Cost$ 3 | Defined$ TriggeredSpellAbility | AILogic$ AlwaysIfViable | MayChooseTarget$ True
Oracle:Whenever you cast an instant or sorcery spell, you may pay {3}. If you do, copy that spell. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/m/mirror_sheen.txt b/forge-gui/res/cardsfolder/m/mirror_sheen.txt
index 490e40e5ba2..0f4c272d652 100644
--- a/forge-gui/res/cardsfolder/m/mirror_sheen.txt
+++ b/forge-gui/res/cardsfolder/m/mirror_sheen.txt
@@ -1,6 +1,5 @@
Name:Mirror Sheen
ManaCost:1 UR UR
Types:Enchantment
-A:AB$ CopySpellAbility | Cost$ 1 UR UR | ValidTgts$ Instant,Sorcery | TargetType$ Spell | TargetValidTargeting$ You | AILogic$ AlwaysIfViable | SpellDescription$ Copy target instant or sorcery spell that targets you. You may choose new targets for the copy.
-SVar:Picture:http://www.wizards.com/global/images/magic/general/mirror_sheen.jpg
+A:AB$ CopySpellAbility | Cost$ 1 UR UR | ValidTgts$ Instant,Sorcery | TargetType$ Spell | TargetValidTargeting$ You | AILogic$ AlwaysIfViable | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell that targets you. You may choose new targets for the copy.
Oracle:{1}{U/R}{U/R}: Copy target instant or sorcery spell that targets you. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/m/mirrorpool.txt b/forge-gui/res/cardsfolder/m/mirrorpool.txt
index b48756c568b..3e9402a00ad 100644
--- a/forge-gui/res/cardsfolder/m/mirrorpool.txt
+++ b/forge-gui/res/cardsfolder/m/mirrorpool.txt
@@ -3,7 +3,6 @@ ManaCost:no cost
Types:Land
K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
-A:AB$ CopySpellAbility | Cost$ 2 C T Sac<1/CARDNAME> | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | TargetType$ Spell | SpellDescription$ Copy target instant or sorcery spell you control. You may choose new targets for the copy.
+A:AB$ CopySpellAbility | Cost$ 2 C T Sac<1/CARDNAME> | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | TargetType$ Spell | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell you control. You may choose new targets for the copy.
A:AB$ CopyPermanent | Cost$ 4 C T Sac<1/CARDNAME> | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | NumCopies$ 1 | SpellDescription$ Create a token that's a copy of target creature you control.
-SVar:Picture:http://www.wizards.com/global/images/magic/general/mirrorpool.jpg
Oracle:Mirrorpool enters the battlefield tapped.\n{T}: Add {C}.\n{2}{C}, {T}, Sacrifice Mirrorpool: Copy target instant or sorcery spell you control. You may choose new targets for the copy.\n{4}{C}, {T}, Sacrifice Mirrorpool: Create a token that's a copy of target creature you control.
diff --git a/forge-gui/res/cardsfolder/m/mischievous_quanar.txt b/forge-gui/res/cardsfolder/m/mischievous_quanar.txt
index ac3499046b8..9351883abc8 100644
--- a/forge-gui/res/cardsfolder/m/mischievous_quanar.txt
+++ b/forge-gui/res/cardsfolder/m/mischievous_quanar.txt
@@ -5,7 +5,7 @@ PT:3/3
K:Morph:1 U U
A:AB$ SetState | Cost$ 3 U U | Defined$ Self | Mode$ TurnFace | SpellDescription$ Turn CARDNAME face down.
T:Mode$ TurnFaceUp | ValidCard$ Card.Self | Execute$ TrigCopy | TriggerZones$ Battlefield | TriggerDescription$ When CARDNAME is turned face up, copy target instant or sorcery spell. You may choose new targets for that copy.
-SVar:TrigCopy:DB$ CopySpellAbility | ValidTgts$ Instant,Sorcery
+SVar:TrigCopy:DB$ CopySpellAbility | ValidTgts$ Instant,Sorcery | MayChooseTarget$ True
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/mischievous_quanar.jpg
Oracle:{3}{U}{U}: Turn Mischievous Quanar face down.\nMorph {1}{U}{U} (You may cast this card face down as a 2/2 creature for {3}. Turn it face up any time for its morph cost.)\nWhen Mischievous Quanar is turned face up, copy target instant or sorcery spell. You may choose new targets for that copy.
diff --git a/forge-gui/res/cardsfolder/n/narset_transcendent.txt b/forge-gui/res/cardsfolder/n/narset_transcendent.txt
index f00e39918ae..61fcf077414 100644
--- a/forge-gui/res/cardsfolder/n/narset_transcendent.txt
+++ b/forge-gui/res/cardsfolder/n/narset_transcendent.txt
@@ -5,11 +5,8 @@ Loyalty:6
A:AB$ PeekAndReveal | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | AILogic$ Main2 | PeekAmount$ 1 | RevealValid$ Card.nonCreature+nonLand | RevealOptional$ True | RememberRevealed$ True | SubAbility$ DBChangeZone | SpellDescription$ Look at the top card of your library. If it's a noncreature, nonland card, you may reveal it and put it into your hand.
SVar:DBChangeZone:DB$ ChangeZone | Defined$ TopOfLibrary | Origin$ Library | Destination$ Hand | ConditionDefined$ Remembered | ConditionPresent$ Card.nonCreature+nonLand | ConditionCompare$ EQ1 | SubAbility$ DBCleanupOne
SVar:DBCleanupOne:DB$ Cleanup | ClearRemembered$ True
-A:AB$Effect | Cost$ SubCounter<2/LOYALTY> | Planeswalker$ True | AILogic$ NarsetRebound | Stackable$ False | Name$ Narset Transcendent effect. | Triggers$ AddRebound | SVars$ AddReboundMain,DBCleanupTwo | SpellDescription$ When you cast your next instant or sorcery spell from your hand this turn, it gains rebound. (Exile the spell as it resolves. At the beginning of your next upkeep, you may cast that card from exile without paying its mana cost.)
-SVar:AddRebound:Mode$ SpellCast | ValidCard$ Instant.wasCastFromHand,Sorcery.wasCastFromHand | ValidActivatingPlayer$ You | OneOff$ True | Execute$ AddReboundMain | TriggerZones$ Command | TriggerDescription$ When you cast your next instant or sorcery spell from your hand this turn, it gains rebound.
-SVar:AddReboundMain:DB$ Pump | Defined$ TriggeredCard| KW$ Rebound | PumpZone$ Stack | SubAbility$ DBCleanupTwo
-SVar:DBCleanupTwo:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
+A:AB$ DelayedTrigger | Cost$ SubCounter<2/LOYALTY> | Planeswalker$ True | AILogic$ NarsetRebound | Stackable$ False | Mode$ SpellCast | ValidCard$ Instant.wasCastFromHand,Sorcery.wasCastFromHand | ValidActivatingPlayer$ You | Execute$ AddRebound | SpellDescription$ When you cast your next instant or sorcery spell from your hand this turn, it gains rebound. (Exile the spell as it resolves. At the beginning of your next upkeep, you may cast that card from exile without paying its mana cost.)
+SVar:AddRebound:DB$ Pump | Defined$ TriggeredCard | KW$ Rebound | PumpZone$ Stack
A:AB$ Effect | Cost$ SubCounter<9/LOYALTY> | Name$ Emblem - Narset Transcendent | StaticAbilities$ STNarset | Planeswalker$ True | Ultimate$ True | Stackable$ False | Duration$ Permanent | AILogic$ Always | SpellDescription$ You get an emblem with "Your opponents can't cast noncreature spells."
SVar:STNarset:Mode$ CantBeCast | ValidCard$ Card.nonCreature | Caster$ Opponent | EffectZone$ Command | Description$ Your opponents can't cast noncreature spells.
-SVar:Picture:http://www.wizards.com/global/images/magic/general/narset_transcendent.jpg
Oracle:[+1]: Look at the top card of your library. If it's a noncreature, nonland card, you may reveal it and put it into your hand.\n[-2]: When you cast your next instant or sorcery spell from your hand this turn, it gains rebound. (Exile the spell as it resolves. At the beginning of your next upkeep, you may cast that card from exile without paying its mana cost.)\n[-9]: You get an emblem with "Your opponents can't cast noncreature spells."
diff --git a/forge-gui/res/cardsfolder/n/narsets_reversal.txt b/forge-gui/res/cardsfolder/n/narsets_reversal.txt
index 8ab37f1b62b..dc0c96b7126 100644
--- a/forge-gui/res/cardsfolder/n/narsets_reversal.txt
+++ b/forge-gui/res/cardsfolder/n/narsets_reversal.txt
@@ -1,6 +1,6 @@
Name:Narset's Reversal
ManaCost:U U
Types:Instant
-A:SP$ CopySpellAbility | Cost$ U U | ValidTgts$ Instant,Sorcery | TargetType$ Spell | SubAbility$ DBReturn | SpellDescription$ Copy target instant or sorcery spell, then return it to its owner's hand. You may choose new targets for the copy.
+A:SP$ CopySpellAbility | Cost$ U U | ValidTgts$ Instant,Sorcery | TargetType$ Spell | SubAbility$ DBReturn | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell, then return it to its owner's hand. You may choose new targets for the copy.
SVar:DBReturn:DB$ChangeZone | Defined$ Targeted | Origin$ Stack | Destination$ Hand
Oracle:Copy target instant or sorcery spell, then return it to its owner's hand. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/n/naru_meha_master_wizard.txt b/forge-gui/res/cardsfolder/n/naru_meha_master_wizard.txt
index b63a4402f64..c14a2b50cd2 100644
--- a/forge-gui/res/cardsfolder/n/naru_meha_master_wizard.txt
+++ b/forge-gui/res/cardsfolder/n/naru_meha_master_wizard.txt
@@ -4,7 +4,7 @@ Types:Legendary Creature Human Wizard
PT:3/3
K:Flash
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigCopy | TriggerDescription$ When CARDNAME enters the battlefield, copy target instant or sorcery spell you control. You may choose new targets for that copy.
-SVar:TrigCopy:DB$ CopySpellAbility | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | TgtPrompt$ Select target instant or sorcery spell you control | TargetType$ Spell
+SVar:TrigCopy:DB$ CopySpellAbility | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | TgtPrompt$ Select target instant or sorcery spell you control | TargetType$ Spell | MayChooseTarget$ True
S:Mode$ Continuous | Affected$ Wizard.Other+YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Other Wizards you control get +1/+1.
DeckHints:Type$Wizard
Oracle:Flash\nWhen Naru Meha, Master Wizard enters the battlefield, copy target instant or sorcery spell you control. You may choose new targets for the copy.\nOther Wizards you control get +1/+1.
diff --git a/forge-gui/res/cardsfolder/n/nivix_guildmage.txt b/forge-gui/res/cardsfolder/n/nivix_guildmage.txt
index 4d82d00d093..c5c5d2e5bb5 100644
--- a/forge-gui/res/cardsfolder/n/nivix_guildmage.txt
+++ b/forge-gui/res/cardsfolder/n/nivix_guildmage.txt
@@ -4,7 +4,6 @@ Types:Creature Human Wizard
PT:2/2
A:AB$ Draw | Cost$ 1 U R | NumCards$ 1 | SpellDescription$ Draw a card, then discard a card. | SubAbility$ DBDiscard
SVar:DBDiscard:DB$Discard | Defined$ You | NumCards$ 1 | Mode$ TgtChoose
-A:AB$ CopySpellAbility | Cost$ 2 U R | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | TargetType$ Spell | AILogic$ OnceIfViable | SpellDescription$ Copy target instant or sorcery spell you control. You may choose new targets for the copy.
+A:AB$ CopySpellAbility | Cost$ 2 U R | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | TargetType$ Spell | AILogic$ OnceIfViable | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell you control. You may choose new targets for the copy.
DeckHints:Type$Instant|Sorcery
-SVar:Picture:http://www.wizards.com/global/images/magic/general/nivix_guildmage.jpg
Oracle:{1}{U}{R}: Draw a card, then discard a card.\n{2}{U}{R}: Copy target instant or sorcery spell you control. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/o/odds_ends.txt b/forge-gui/res/cardsfolder/o/odds_ends.txt
index 7b9f91cede5..3dea750bd26 100644
--- a/forge-gui/res/cardsfolder/o/odds_ends.txt
+++ b/forge-gui/res/cardsfolder/o/odds_ends.txt
@@ -4,8 +4,7 @@ AlternateMode: Split
Types:Instant
A:SP$ FlipACoin | Cost$ U R | NoCall$ True | HeadsSubAbility$ OddCounter | TailsSubAbility$ OddCopy | TgtZone$ Stack | TargetType$ Spell | ValidTgts$ Instant,Sorcery | TgtPrompt$ Select target Instant or Sorcery spell | SpellDescription$ Flip a coin. If it comes up heads, counter target instant or sorcery spell. If it comes up tails, copy that spell and you may choose new targets for the copy.
SVar:OddCounter:DB$ Counter | Defined$ Targeted
-SVar:OddCopy:DB$ CopySpellAbility | Defined$ Targeted
-SVar:Picture:http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=107445&type=card
+SVar:OddCopy:DB$ CopySpellAbility | Defined$ Targeted | MayChooseTarget$ True
Oracle:Flip a coin. If it comes up heads, counter target instant or sorcery spell. If it comes up tails, copy that spell and you may choose new targets for the copy.
ALTERNATE
diff --git a/forge-gui/res/cardsfolder/p/primal_amulet_primal_wellspring.txt b/forge-gui/res/cardsfolder/p/primal_amulet_primal_wellspring.txt
index 51900199f54..d9036d6f932 100644
--- a/forge-gui/res/cardsfolder/p/primal_amulet_primal_wellspring.txt
+++ b/forge-gui/res/cardsfolder/p/primal_amulet_primal_wellspring.txt
@@ -13,7 +13,6 @@ T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | Execute$ DBInitSV
SVar:DBInitSVar:DB$ StoreSVar | SVar$ FullyCharged | Type$ Number | Expression$ 0 | References$ FullyCharged
SVar:FullyCharged:Number$0
AlternateMode:DoubleFaced
-SVar:Picture:http://www.wizards.com/global/images/magic/general/primal_amulet.jpg
Oracle:Instant and sorcery spells you cast cost {1} less to cast.\nWhenever you cast an instant or sorcery spell, put a charge counter on Primal Amulet. Then if there are four or more charge counters on it, you may remove those counters and transform it.
ALTERNATE
@@ -23,6 +22,5 @@ ManaCost:no cost
Types:Land
A:AB$ Mana | Cost$ T | Produced$ Any | TriggersWhenSpent$ TrigCopy | SpellDescription$ Add one mana of any color. When that mana is spent to cast an instant or sorcery spell, copy that spell and you may choose new targets for the copy.
SVar:TrigCopy:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | OneOff$ True | Execute$ TrigCopyMain | TriggerDescription$ When that mana is spent to cast an instant or sorcery spell, copy that spell and you may choose new targets for the copy.
-SVar:TrigCopyMain:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility
-SVar:Picture:http://www.wizards.com/global/images/magic/general/primal_wellspring.jpg
+SVar:TrigCopyMain:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
Oracle:(Transforms from Primal Amulet.)\n{T}: Add one mana of any color. When that mana is spent to cast an instant or sorcery spell, copy that spell and you may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/p/psychic_rebuttal.txt b/forge-gui/res/cardsfolder/p/psychic_rebuttal.txt
index 4ab4bdebbc8..89afa121899 100644
--- a/forge-gui/res/cardsfolder/p/psychic_rebuttal.txt
+++ b/forge-gui/res/cardsfolder/p/psychic_rebuttal.txt
@@ -2,8 +2,7 @@ Name:Psychic Rebuttal
ManaCost:1 U
Types:Instant
A:SP$ Counter | Cost$ 1 U | TargetType$ Spell | TargetValidTargeting$ You | TgtPrompt$ Select target spell that targets you | ValidTgts$ Instant,Sorcery | RememberCountered$ True | SubAbility$ DBCopy | SpellDescription$ Counter target instant or sorcery spell that targets you. Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, you may copy the spell countered this way. You may choose new targets for the copy.
-SVar:DBCopy:DB$ CopySpellAbility | Defined$ Remembered | ConditionCheckSVar$ X | ConditionSVarCompare$ GE2 | References$ X | SubAbility$ DBCleanup
+SVar:DBCopy:DB$ CopySpellAbility | Defined$ Remembered | ConditionCheckSVar$ X | ConditionSVarCompare$ GE2 | References$ X | MayChooseTarget$ True | SubAbility$ DBCleanup
SVar:X:Count$ValidGraveyard Instant.YouOwn,Sorcery.YouOwn
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
-SVar:Picture:http://www.wizards.com/global/images/magic/general/psychic_rebuttal.jpg
-Oracle:Counter target instant or sorcery spell that targets you. \nSpell mastery — If there are two or more instant and/or sorcery cards in your graveyard, you may copy the spell countered this way. You may choose new targets for the copy.
\ No newline at end of file
+Oracle:Counter target instant or sorcery spell that targets you. \nSpell mastery — If there are two or more instant and/or sorcery cards in your graveyard, you may copy the spell countered this way. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/p/pyromancer_ascension.txt b/forge-gui/res/cardsfolder/p/pyromancer_ascension.txt
index d04969a0e6a..e94edad87cc 100644
--- a/forge-gui/res/cardsfolder/p/pyromancer_ascension.txt
+++ b/forge-gui/res/cardsfolder/p/pyromancer_ascension.txt
@@ -3,11 +3,10 @@ ManaCost:1 R
Types:Enchantment
T:Mode$ SpellCast | ValidCard$ Instant.sharesNameWith YourGraveyard,Sorcery.sharesNameWith YourGraveyard | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPutCounter | OptionalDecider$ You | TriggerDescription$ Whenever you cast an instant or sorcery spell that has the same name as a card in your graveyard, you may put a quest counter on CARDNAME.
T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | IsPresent$ Card.Self+counters_GE2_QUEST | Execute$ TrigCopySpell | OptionalDecider$ You | TriggerDescription$ Whenever you cast an instant or sorcery spell while CARDNAME has two or more quest counters on it, you may copy that spell. You may choose new targets for the copy.
-SVar:TrigPutCounter:DB$PutCounter | Defined$ Self | CounterType$ QUEST | CounterNum$ 1 | ConditionDefined$ TriggeredCard
-SVar:TrigCopySpell:DB$CopySpellAbility | Defined$ TriggeredSpellAbility | AILogic$ Always
+SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ QUEST | CounterNum$ 1 | ConditionDefined$ TriggeredCard
+SVar:TrigCopySpell:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | AILogic$ Always | MayChooseTarget$ True
DeckHints:Keyword$Retrace & Keyword$Flashback
DeckNeeds:Type$Instant|Sorcery
DeckHas:Ability$Counters
SVar:MaxQuestEffect:2
-SVar:Picture:http://www.wizards.com/global/images/magic/general/pyromancer_ascension.jpg
Oracle:Whenever you cast an instant or sorcery spell that has the same name as a card in your graveyard, you may put a quest counter on Pyromancer Ascension.\nWhenever you cast an instant or sorcery spell while Pyromancer Ascension has two or more quest counters on it, you may copy that spell. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/p/pyromancers_goggles.txt b/forge-gui/res/cardsfolder/p/pyromancers_goggles.txt
index f44a6f5cc23..b3ebf4655db 100644
--- a/forge-gui/res/cardsfolder/p/pyromancers_goggles.txt
+++ b/forge-gui/res/cardsfolder/p/pyromancers_goggles.txt
@@ -3,6 +3,5 @@ ManaCost:5
Types:Legendary Artifact
A:AB$ Mana | Cost$ T | Produced$ R | TriggersWhenSpent$ TrigCopy | SpellDescription$ Add {R}. When that mana is spent to cast a red instant or sorcery spell, copy that spell and you may choose new targets for the copy.
SVar:TrigCopy:Mode$ SpellCast | ValidCard$ Instant.Red,Sorcery.Red | ValidActivatingPlayer$ You | OneOff$ True | Execute$ TrigCopyMain | TriggerDescription$ When that mana is spent to cast a red instant or sorcery spell, copy that spell and you may choose new targets for the copy.
-SVar:TrigCopyMain:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility
-SVar:Picture:http://www.wizards.com/global/images/magic/general/pyromancers_goggles.jpg
-Oracle:{T}: Add {R}. When that mana is spent to cast a red instant or sorcery spell, copy that spell and you may choose new targets for the copy.
\ No newline at end of file
+SVar:TrigCopyMain:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
+Oracle:{T}: Add {R}. When that mana is spent to cast a red instant or sorcery spell, copy that spell and you may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/r/ral_storm_conduit.txt b/forge-gui/res/cardsfolder/r/ral_storm_conduit.txt
index 1b326d0ee86..22928716d85 100644
--- a/forge-gui/res/cardsfolder/r/ral_storm_conduit.txt
+++ b/forge-gui/res/cardsfolder/r/ral_storm_conduit.txt
@@ -6,10 +6,8 @@ T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | Tr
T:Mode$ SpellCopy | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigDealDamage | Secondary$ True | TriggerDescription$ Whenever you cast or copy an instant or sorcery spell, CARDNAME deals 1 damage to target opponent or planeswalker.
SVar:TrigDealDamage:DB$DealDamage | ValidTgts$ Opponent,Planeswalker | TgtPrompt$ Select target opponent or planeswalker | NumDmg$ 1
A:AB$ Scry | Cost$ AddCounter<2/LOYALTY> | Planeswalker$ True | ScryNum$ 1 | SpellDescription$ Scry 1.
-A:AB$ Effect | Cost$ SubCounter<2/LOYALTY> | Planeswalker$ True | AILogic$ SpellCopy | Triggers$ EffTModeSpellCast | SVars$ EffTrigCopy,EffDBCleanup | SpellDescription$ When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.
-SVar:EffTModeSpellCast:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | OneOff$ True | Execute$ EffTrigCopy | TriggerZones$ Command | TriggerDescription$ When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.
-SVar:EffTrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | SubAbility$ EffDBCleanup
-SVar:EffDBCleanup:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
+A:AB$ DelayedTrigger | Cost$ SubCounter<2/LOYALTY> | Planeswalker$ True | AILogic$ SpellCopy | Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | ThisTurn$ True | Execute$ EffTrigCopy | SpellDescription$ When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.
+SVar:EffTrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
SVar:BuffedBy:Instant,Sorcery
DeckHints:Type$Instant|Sorcery
Oracle:Whenever you cast or copy an instant or sorcery spell, Ral, Storm Conduit deals 1 damage to target opponent or planeswalker.\n[+2]: Scry 1.\n[-2]: When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/r/refuse_cooperate.txt b/forge-gui/res/cardsfolder/r/refuse_cooperate.txt
index 3faa79eb7d1..e2e589b9b59 100644
--- a/forge-gui/res/cardsfolder/r/refuse_cooperate.txt
+++ b/forge-gui/res/cardsfolder/r/refuse_cooperate.txt
@@ -3,11 +3,9 @@ ManaCost:3 R
AlternateMode: Split
Types:Instant
A:SP$ Pump | Cost$ 3 R | ValidTgts$ Card | TgtZone$ Stack | TgtPrompt$ Select target spell | PumpZone$ Stack | StackDescription$ None | SubAbility$ DBDmg | SpellDescription$ CARDNAME deals damage to target spell's controller equal to that spell's converted mana cost.
-
SVar:DBDmg:DB$ DealDamage | Defined$ TargetedController | NumDmg$ X | References$ X
SVar:X:Targeted$CardManaCost
AI:RemoveDeck:All
-SVar:Picture:http://www.wizards.com/global/images/magic/general/refuse_cooperate.jpg
Oracle:Refuse deals damage to target spell's controller equal to that spell's converted mana cost.
ALTERNATE
@@ -16,5 +14,5 @@ Name:Cooperate
ManaCost:2 U
Types:Instant
K:Aftermath
-A:SP$ CopySpellAbility | Cost$ 2 U | ValidTgts$ Instant,Sorcery | TargetType$ Spell | SpellDescription$ Copy target instant or sorcery spell. You may choose new targets for the copy.
-Oracle:Aftermath (Cast this spell only from your graveyard. Then exile it.)\nCopy target instant or sorcery spell. You may choose new targets for the copy.
\ No newline at end of file
+A:SP$ CopySpellAbility | Cost$ 2 U | ValidTgts$ Instant,Sorcery | TargetType$ Spell | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell. You may choose new targets for the copy.
+Oracle:Aftermath (Cast this spell only from your graveyard. Then exile it.)\nCopy target instant or sorcery spell. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/r/reiterate.txt b/forge-gui/res/cardsfolder/r/reiterate.txt
index 3fcbd34eb41..1ffaf9fa118 100644
--- a/forge-gui/res/cardsfolder/r/reiterate.txt
+++ b/forge-gui/res/cardsfolder/r/reiterate.txt
@@ -2,6 +2,5 @@ Name:Reiterate
ManaCost:1 R R
Types:Instant
K:Buyback:3
-A:SP$ CopySpellAbility | Cost$ 1 R R | ValidTgts$ Instant,Sorcery | TargetType$ Spell | SpellDescription$ Copy target instant or sorcery spell. You may choose new targets for the copy.
-SVar:Picture:http://www.wizards.com/global/images/magic/general/reiterate.jpg
+A:SP$ CopySpellAbility | Cost$ 1 R R | ValidTgts$ Instant,Sorcery | TargetType$ Spell | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell. You may choose new targets for the copy.
Oracle:Buyback {3} (You may pay an additional {3} as you cast this spell. If you do, put this card into your hand as it resolves.)\nCopy target instant or sorcery spell. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/r/repeated_reverberation.txt b/forge-gui/res/cardsfolder/r/repeated_reverberation.txt
index e3929f56fbc..9f28c457011 100644
--- a/forge-gui/res/cardsfolder/r/repeated_reverberation.txt
+++ b/forge-gui/res/cardsfolder/r/repeated_reverberation.txt
@@ -1,9 +1,6 @@
Name:Repeated Reverberation
ManaCost:2 R R
Types:Instant
-A:SP$ Effect | Cost$ 2 R R | AILogic$ SpellCopy | Name$ Repeated Reverberation Effect | Triggers$ TrigCopy,TrigCopy2 | SVars$ TrigCopyMain,DBCleanup | SpellDescription$ When you next cast an instant spell, cast a sorcery spell, or activate a loyalty ability this turn, copy that spell or ability twice. You may choose new targets for the copies.
-SVar:TrigCopy:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | OneOff$ True | Execute$ TrigCopyMain | TriggerZones$ Command | TriggerDescription$ When you next cast an instant spell, cast a sorcery spell, or activate a loyalty ability this turn, copy that spell or ability twice. You may choose new targets for the copies.
-SVar:TrigCopy2:Mode$ AbilityCast | ValidSA$ Activated.Loyalty | ValidActivatingPlayer$ You | OneOff$ True | Execute$ TrigCopyMain | TriggerZones$ Command | Secondary$ True | TriggerDescription$ When you next cast an instant spell, cast a sorcery spell, or activate a loyalty ability this turn, copy that spell or ability twice. You may choose new targets for the copies.
-SVar:TrigCopyMain:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ 2 | SubAbility$ DBCleanup
-SVar:DBCleanup:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
+A:SP$ DelayedTrigger | Cost$ 2 R R | AILogic$ SpellCopy | Mode$ SpellAbilityCast | ValidSA$ Spell.Instant,Spell.Sorcery,Activated.Loyalty | ValidActivatingPlayer$ You | ThisTurn$ True | Execute$ EffTrigCopy | SpellDescription$ When you next cast an instant spell, cast a sorcery spell, or activate a loyalty ability this turn, copy that spell or ability twice. You may choose new targets for the copies.
+SVar:EffTrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ 2 | MayChooseTarget$ True
Oracle:When you next cast an instant spell, cast a sorcery spell, or activate a loyalty ability this turn, copy that spell or ability twice. You may choose new targets for the copies.
diff --git a/forge-gui/res/cardsfolder/r/reverberate.txt b/forge-gui/res/cardsfolder/r/reverberate.txt
index 2cea6ba32d5..fdbecf88327 100644
--- a/forge-gui/res/cardsfolder/r/reverberate.txt
+++ b/forge-gui/res/cardsfolder/r/reverberate.txt
@@ -1,6 +1,5 @@
Name:Reverberate
ManaCost:R R
Types:Instant
-A:SP$ CopySpellAbility | Cost$ R R | ValidTgts$ Instant,Sorcery | TargetType$ Spell | SpellDescription$ Copy target instant or sorcery spell. You may choose new targets for the copy.
-SVar:Picture:http://www.wizards.com/global/images/magic/general/reverberate.jpg
+A:SP$ CopySpellAbility | Cost$ R R | ValidTgts$ Instant,Sorcery | TargetType$ Spell | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell. You may choose new targets for the copy.
Oracle:Copy target instant or sorcery spell. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/r/riku_of_two_reflections.txt b/forge-gui/res/cardsfolder/r/riku_of_two_reflections.txt
index 1f9f406f0af..bb1fb53aab7 100644
--- a/forge-gui/res/cardsfolder/r/riku_of_two_reflections.txt
+++ b/forge-gui/res/cardsfolder/r/riku_of_two_reflections.txt
@@ -4,7 +4,6 @@ Types:Legendary Creature Human Wizard
PT:2/2
T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigCopySpell | TriggerDescription$ Whenever you cast an instant or sorcery spell, you may pay {U}{R}. If you do, copy that spell. You may choose new targets for the copy.
T:Mode$ ChangesZone | ValidCard$ Creature.nonToken+Other+YouCtrl | Origin$ Any | Destination$ Battlefield | TriggerZones$ Battlefield | Execute$ TrigCopy | OptionalDecider$ You | TriggerDescription$ Whenever another nontoken creature enters the battlefield under your control, you may pay {G}{U}. If you do, create a token that's a copy of that creature.
-SVar:TrigCopySpell:AB$CopySpellAbility | Cost$ U R | Defined$ TriggeredSpellAbility
-SVar:TrigCopy:AB$CopyPermanent | Cost$ G U | Defined$ TriggeredCard
-SVar:Picture:http://www.wizards.com/global/images/magic/general/riku_of_two_reflections.jpg
+SVar:TrigCopySpell:AB$ CopySpellAbility | Cost$ U R | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
+SVar:TrigCopy:AB$ CopyPermanent | Cost$ G U | Defined$ TriggeredCard
Oracle:Whenever you cast an instant or sorcery spell, you may pay {U}{R}. If you do, copy that spell. You may choose new targets for the copy.\nWhenever another nontoken creature enters the battlefield under your control, you may pay {G}{U}. If you do, create a token that's a copy of that creature.
diff --git a/forge-gui/res/cardsfolder/r/rings_of_brighthearth.txt b/forge-gui/res/cardsfolder/r/rings_of_brighthearth.txt
index e21f20983e6..956342757ca 100644
--- a/forge-gui/res/cardsfolder/r/rings_of_brighthearth.txt
+++ b/forge-gui/res/cardsfolder/r/rings_of_brighthearth.txt
@@ -2,6 +2,5 @@ Name:Rings of Brighthearth
ManaCost:3
Types:Artifact
T:Mode$ AbilityCast | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigCopySpell | OptionalDecider$ You | TriggerDescription$ Whenever you activate an ability, if it isn't a mana ability, you may pay {2}. If you do, copy that ability. You may choose new targets for the copy.
-SVar:TrigCopySpell:AB$CopySpellAbility | Cost$ 2 | Defined$ TriggeredSpellAbility
-SVar:Picture:http://www.wizards.com/global/images/magic/general/rings_of_brighthearth.jpg
+SVar:TrigCopySpell:AB$ CopySpellAbility | Cost$ 2 | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
Oracle:Whenever you activate an ability, if it isn't a mana ability, you may pay {2}. If you do, copy that ability. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/r/rowan_kenrith.txt b/forge-gui/res/cardsfolder/r/rowan_kenrith.txt
index 302a8e04b57..ef4d73251d9 100644
--- a/forge-gui/res/cardsfolder/r/rowan_kenrith.txt
+++ b/forge-gui/res/cardsfolder/r/rowan_kenrith.txt
@@ -12,6 +12,6 @@ SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
A:AB$ DamageAll | Cost$ SubCounter<2/LOYALTY> | ValidTgts$ Player | TgtPrompt$ Select target player | NumDmg$ 3 | ValidCards$ Creature.tapped | Planeswalker$ True | ValidDescription$ each tapped creature target player controls. | SpellDescription$ CARDNAME deals 3 damage to each tapped creature target player controls
A:AB$ Effect | Cost$ SubCounter<8/LOYALTY> | Planeswalker$ True | Ultimate$ True | ValidTgts$ Player | EffectOwner$ Targeted | Name$ Emblem - Rowan Kenrith | Image$ emblem_rowan_kenrith | Triggers$ CopyAbility | SVars$ TrigCopy | Duration$ Permanent | AILogic$ Always | SpellDescription$ Target player gets an emblem with "Whenever you activate an ability that isn't a mana ability, copy it. You may choose new targets for the copy."
SVar:CopyAbility:Mode$ AbilityCast | ValidActivatingPlayer$ You | TriggerZones$ Command | Execute$ TrigCopy | TriggerDescription$ Whenever you activate an ability that isn't a mana ability, copy it. You may choose new targets for the copy.
-SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility
+SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
DeckHints:Name$Will Kenrith
Oracle:[+2]: During target player's next turn, each creature that player controls attacks if able.\n[-2]: Rowan Kenrith deals 3 damage to each tapped creature target player controls.\n[-8]: Target player gets an emblem with "Whenever you activate an ability that isn't a mana ability, copy it. You may choose new targets for the copy."\nPartner with Will Kenrith\nRowan Kenrith can be your commander.\n
diff --git a/forge-gui/res/cardsfolder/s/sea_gate_stormcaller.txt b/forge-gui/res/cardsfolder/s/sea_gate_stormcaller.txt
index bb79544f84d..c4e60d7f6e5 100755
--- a/forge-gui/res/cardsfolder/s/sea_gate_stormcaller.txt
+++ b/forge-gui/res/cardsfolder/s/sea_gate_stormcaller.txt
@@ -3,14 +3,10 @@ ManaCost:1 U
Types:Creature Human Wizard
PT:2/1
K:Kicker:4 U
+T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigEffect | TriggerDescription$ When CARDNAME enters the battlefield, copy the next instant or sorcery spell with converted mana cost 2 or less you cast this turn when you cast it. You may choose new targets for the copy.
+SVar:TrigEffect:DB$ DelayedTrigger | AILogic$ SpellCopy | Mode$ SpellCast | ValidCard$ Instant.cmcLE2,Sorcery.cmcLE2 | ValidActivatingPlayer$ You | ThisTurn$ True | Execute$ TrigCopy | TriggerDescription$ Copy the next instant or sorcery spell with converted mana cost 2 or less you cast this turn when you cast it. You may choose new targets for the copy.
+SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | AILogic$ Always | Amount$ X | References$ X | MayChooseTarget$ True
+SVar:X:Count$Kicked.2.1
SVar:PlayMain1:TRUE
-T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self+notkicked | Execute$ TrigEffect | Secondary$ True | TriggerDescription$ When CARDNAME enters the battlefield, copy the next instant or sorcery spell with converted mana cost 2 or less you cast this turn when you cast it. You may choose new targets for the copy.
-T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self+kicked | Execute$ TrigEffectKicked | TriggerDescription$ When CARDNAME enters the battlefield, copy the next instant or sorcery spell with converted mana cost 2 or less you cast this turn when you cast it. If CARDNAME was kicked, copy that spell twice instead. You may choose new targets for the copies.
-SVar:TrigEffect:DB$ Effect | Triggers$ TrigCast | SVars$ TrigCopy
-SVar:TrigCast:Mode$ SpellCast | OneOff$ True | ValidActivatingPlayer$ You | ValidCard$ Instant.cmcLE2,Sorcery.cmcLE2 | TriggerZones$ Command | Execute$ TrigCopy | TriggerDescription$ Copy the next instant or sorcery spell with converted mana cost 2 or less you cast this turn when you cast it. You may choose new targets for the copy.
-SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | AILogic$ Always
-SVar:TrigEffectKicked:DB$ Effect | Triggers$ TrigCastKicked | SVars$ TrigCopyKicked
-SVar:TrigCastKicked:Mode$ SpellCast | OneOff$ True | ValidActivatingPlayer$ You | ValidCard$ Instant.cmcLE2,Sorcery.cmcLE2 | TriggerZones$ Command | Execute$ TrigCopyKicked | TriggerDescription$ Copy the next instant or sorcery spell with converted mana cost 2 or less you cast this turn twice when you cast it. You may choose new targets for the copies.
-SVar:TrigCopyKicked:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | AILogic$ Always | Amount$ 2
DeckNeeds:Type$Instant|Sorcery
Oracle:Kicker {4}{U}\nWhen Sea Gate Stormcaller enters the battlefield, copy the next instant or sorcery spell with converted mana cost 2 or less you cast this turn when you cast it. If Sea Gate Stormcaller was kicked, copy that spell twice instead. You may choose new targets for the copies.
diff --git a/forge-gui/res/cardsfolder/s/sevinne_the_chronoclasm.txt b/forge-gui/res/cardsfolder/s/sevinne_the_chronoclasm.txt
index f06d2b1f5be..f5ea7aaa247 100644
--- a/forge-gui/res/cardsfolder/s/sevinne_the_chronoclasm.txt
+++ b/forge-gui/res/cardsfolder/s/sevinne_the_chronoclasm.txt
@@ -4,6 +4,6 @@ Types:Legendary Creature Human Wizard
PT:2/2
K:Prevent all damage that would be dealt to CARDNAME.
T:Mode$ SpellCast | ValidCard$ Instant.YouCtrl+wasCastFromGraveyard,Sorcery.YouCtrl+wasCastFromGraveyard | ActivatorThisTurnCast$ EQ1 | NoResolvingCheck$ True | ValidActivatingPlayer$ You | Execute$ TrigCopy | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast your first instant or sorcery spell from your graveyard each turn, copy that spell. You may choose new targets for the copy.
-SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility
+SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
SVar:AIPriorityModifier:9
Oracle:Prevent all damage that would be dealt to Sevinne, the Chronoclasm.\nWhenever you cast your first instant or sorcery spell from your graveyard each turn, copy that spell. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/s/sevinnes_reclamation.txt b/forge-gui/res/cardsfolder/s/sevinnes_reclamation.txt
index 8cc7d22d078..5d5965771d6 100644
--- a/forge-gui/res/cardsfolder/s/sevinnes_reclamation.txt
+++ b/forge-gui/res/cardsfolder/s/sevinnes_reclamation.txt
@@ -2,7 +2,7 @@ Name:Sevinne's Reclamation
ManaCost:2 W
Types:Sorcery
A:SP$ ChangeZone | Cost$ 2 W | Origin$ Graveyard | Destination$ Battlefield | TgtPrompt$ Choose target permanent card with converted mana cost 3 or less from your graveyard | ValidTgts$ Permanent.cmcLE3+YouCtrl | SubAbility$ DBCpoy | SpellDescription$ Return target permanent card with converted mana cost 3 or less from your graveyard to the battlefield. If this spell was cast from a graveyard, you may copy this spell and may choose a new target for the copy.
-SVar:DBCpoy:DB$ CopySpellAbility | Defined$ Parent | Optional$ True | ConditionDefined$ Self | ConditionPresent$ Card.wasCastFromGraveyard
+SVar:DBCpoy:DB$ CopySpellAbility | Defined$ Parent | Optional$ True | MayChooseTarget$ True | ConditionDefined$ Self | ConditionPresent$ Card.wasCastFromGraveyard
AI:RemoveDeck:Random
K:Flashback:4 W
Oracle:Return target permanent card with converted mana cost 3 or less from your graveyard to the battlefield. If this spell was cast from a graveyard, you may copy this spell and may choose a new target for the copy.\nFlashback {4}{W} (You may cast this card from your graveyard for its flashback cost. Then exile it.)
diff --git a/forge-gui/res/cardsfolder/s/sigil_tracer.txt b/forge-gui/res/cardsfolder/s/sigil_tracer.txt
index 1cdca3526fe..09b58c48055 100644
--- a/forge-gui/res/cardsfolder/s/sigil_tracer.txt
+++ b/forge-gui/res/cardsfolder/s/sigil_tracer.txt
@@ -2,6 +2,5 @@ Name:Sigil Tracer
ManaCost:1 U U
Types:Creature Merfolk Wizard
PT:2/2
-A:AB$CopySpellAbility | Cost$ 1 U tapXType<2/Wizard> | ValidTgts$ Instant,Sorcery | AILogic$ OnceIfViable | SpellDescription$ Copy target instant or sorcery spell. You may choose new targets for the copy.
-SVar:Picture:http://www.wizards.com/global/images/magic/general/sigil_tracer.jpg
+A:AB$CopySpellAbility | Cost$ 1 U tapXType<2/Wizard> | ValidTgts$ Instant,Sorcery | AILogic$ OnceIfViable | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell. You may choose new targets for the copy.
Oracle:{1}{U}, Tap two untapped Wizards you control: Copy target instant or sorcery spell. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/s/skull_storm.txt b/forge-gui/res/cardsfolder/s/skull_storm.txt
index 8575431914b..eb34c18aeb9 100644
--- a/forge-gui/res/cardsfolder/s/skull_storm.txt
+++ b/forge-gui/res/cardsfolder/s/skull_storm.txt
@@ -2,7 +2,7 @@ Name:Skull Storm
ManaCost:7 B B
Types:Sorcery
T:Mode$ SpellCast | ValidCard$ Card.Self | Execute$ TrigCopy | TriggerDescription$ When you cast this spell, copy it for each time you've cast your commander from the command zone this game.
-SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ X | References$ X
+SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ X | References$ X | MayChooseTarget$ True
SVar:X:Count$TotalCommanderCastFromCommandZone
A:SP$ Sacrifice | Cost$ 7 B B | Defined$ Player.Opponent | SacValid$ Creature | RememberSacrificed$ True | SubAbility$ DBRepeatEach
SVar:DBRepeatEach:DB$ RepeatEach | RepeatPlayers$ Player.Opponent | RepeatSubAbility$ DBLoseLife | SubAbility$ DBCleanup
diff --git a/forge-gui/res/cardsfolder/s/spelltwine.txt b/forge-gui/res/cardsfolder/s/spelltwine.txt
index 87e3b6f5ec5..5c401b433fe 100644
--- a/forge-gui/res/cardsfolder/s/spelltwine.txt
+++ b/forge-gui/res/cardsfolder/s/spelltwine.txt
@@ -3,9 +3,8 @@ ManaCost:5 U
Types:Sorcery
A:SP$ ChangeZone | Cost$ 5 U | Origin$ Graveyard | Destination$ Exile | TgtPrompt$ Choose target instant or sorcery card in your graveyard | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | RememberChanged$ True | SubAbility$ TgtOpp | SpellDescription$ Exile target instant or sorcery card from your graveyard and target instant or sorcery from your opponent's graveyard. Copy those cards. Cast the copies if able without paying their mana cost.
SVar:TgtOpp:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | TgtPrompt$ Choose target instant or sorcery card in your opponent's graveyard | ValidTgts$ Instant.OppOwn,Sorcery.OppOwn | RememberChanged$ True | SubAbility$ CopyYou
-SVar:CopyYou:DB$ CopySpellAbility | Defined$ Remembered | SubAbility$ CopyOpp | CopyMultipleSpells$ 2 | SubAbility$ ExileSelf
+SVar:CopyYou:DB$ Play | Defined$ Remembered | Amount$ All | CopyCard$ True | WithoutManaCost$ True | SubAbility$ ExileSelf
SVar:ExileSelf:DB$ ChangeZone | Origin$ Stack | Destination$ Exile | Defined$ Self | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
AI:RemoveDeck:All
-SVar:Picture:http://www.wizards.com/global/images/magic/general/spelltwine.jpg
Oracle:Exile target instant or sorcery card from your graveyard and target instant or sorcery card from an opponent's graveyard. Copy those cards. Cast the copies if able without paying their mana costs. Exile Spelltwine.
diff --git a/forge-gui/res/cardsfolder/s/split_decision.txt b/forge-gui/res/cardsfolder/s/split_decision.txt
index 85c1a30fc3b..8cdae3d0a57 100644
--- a/forge-gui/res/cardsfolder/s/split_decision.txt
+++ b/forge-gui/res/cardsfolder/s/split_decision.txt
@@ -3,7 +3,6 @@ ManaCost:1 U
Types:Instant
A:SP$ Vote | Cost$ 1 U | ValidTgts$ Instant,Sorcery | TgtZone$ Stack | TargetType$ Spell | Defined$ Player | VoteDenial$ DBDenial | VoteDuplication$ DBDuplication | Tied$ DBDuplication | VoteType$ Denial,Duplication | SpellDescription$ Will of the Council — Choose target instant or sorcery spell. Starting with you, each player votes for denial or duplication. If denial gets more votes, counter that spell. If duplication gets more votes or the vote is tied, copy the spell. You may choose new targets for the copy.
SVar:DBDenial:DB$ Counter | Defined$ Targeted
-SVar:DBDuplication:DB$ CopySpellAbility | Defined$ Targeted
+SVar:DBDuplication:DB$ CopySpellAbility | Defined$ Targeted | MayChooseTarget$ True
AI:RemoveDeck:All
-SVar:Picture:http://www.wizards.com/global/images/magic/general/split_decision.jpg
Oracle:Will of the council — Choose target instant or sorcery spell. Starting with you, each player votes for denial or duplication. If denial gets more votes, counter the spell. If duplication gets more votes or the vote is tied, copy the spell. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/s/string_of_disappearances.txt b/forge-gui/res/cardsfolder/s/string_of_disappearances.txt
index 446129daac2..b45f42c0e83 100644
--- a/forge-gui/res/cardsfolder/s/string_of_disappearances.txt
+++ b/forge-gui/res/cardsfolder/s/string_of_disappearances.txt
@@ -2,5 +2,5 @@ Name:String of Disappearances
ManaCost:U
Types:Instant
A:SP$ ChangeZone | Cost$ U | ValidTgts$ Creature | TgtPrompt$ Select target creature | Origin$ Battlefield | Destination$ Hand | SubAbility$ DBCopy | SpellDescription$ Return target creature to its owner's hand. Then that creature's controller may pay {U}{U}. If the player does, they may copy this spell and may choose a new target for that copy.
-SVar:DBCopy:DB$ CopySpellAbility | Defined$ Parent | Controller$ TargetedController | UnlessPayer$ TargetedController | UnlessCost$ U U | UnlessSwitched$ True | ConditionDefined$ Targeted | ConditionPresent$ Permanent | ConditionCompare$ GE1 | StackDescription$ None
+SVar:DBCopy:DB$ CopySpellAbility | Defined$ Parent | Controller$ TargetedController | UnlessPayer$ TargetedController | UnlessCost$ U U | UnlessSwitched$ True | ConditionDefined$ Targeted | ConditionPresent$ Permanent | ConditionCompare$ GE1 | StackDescription$ None | MayChooseTarget$ True
Oracle:Return target creature to its owner's hand. Then that creature's controller may pay {U}{U}. If the player does, they may copy this spell and may choose a new target for that copy.
diff --git a/forge-gui/res/cardsfolder/s/strionic_resonator.txt b/forge-gui/res/cardsfolder/s/strionic_resonator.txt
index d24f160d254..b043b300c75 100644
--- a/forge-gui/res/cardsfolder/s/strionic_resonator.txt
+++ b/forge-gui/res/cardsfolder/s/strionic_resonator.txt
@@ -1,8 +1,7 @@
Name:Strionic Resonator
ManaCost:2
Types:Artifact
-A:AB$ CopySpellAbility | Cost$ 2 T | TargetType$ Triggered.YouCtrl | ValidTgts$ Card | SpellDescription$ Copy target triggered ability you control. You may choose new targets for the copy.
+A:AB$ CopySpellAbility | Cost$ 2 T | TargetType$ Triggered.YouCtrl | ValidTgts$ Card | MayChooseTarget$ True | SpellDescription$ Copy target triggered ability you control. You may choose new targets for the copy.
AI:RemoveDeck:All
AI:RemoveDeck:Random
-SVar:Picture:http://www.wizards.com/global/images/magic/general/strionic_resonator.jpg
Oracle:{2}, {T}: Copy target triggered ability you control. You may choose new targets for the copy. (A triggered ability uses the words "when," "whenever," or "at.")
diff --git a/forge-gui/res/cardsfolder/s/swarm_intelligence.txt b/forge-gui/res/cardsfolder/s/swarm_intelligence.txt
index d0b3eda2a2d..6cd271abf27 100644
--- a/forge-gui/res/cardsfolder/s/swarm_intelligence.txt
+++ b/forge-gui/res/cardsfolder/s/swarm_intelligence.txt
@@ -2,8 +2,7 @@ Name:Swarm Intelligence
ManaCost:6 U
Types:Enchantment
T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | Execute$ TrigCopySpell | OptionalDecider$ You | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast an instant or sorcery spell, you may copy that spell. You may choose new targets for the copy.
-SVar:TrigCopySpell:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | AILogic$ Always
+SVar:TrigCopySpell:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | AILogic$ Always | MayChooseTarget$ True
DeckHints:Keyword$Retrace & Keyword$Flashback
DeckNeeds:Type$Instant|Sorcery
-SVar:Picture:http://www.wizards.com/global/images/magic/general/swarm_intelligence.jpg
Oracle:Whenever you cast an instant or sorcery spell, you may copy that spell. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/t/tawnos_urzas_apprentice.txt b/forge-gui/res/cardsfolder/t/tawnos_urzas_apprentice.txt
index 24714b0ad0e..6b75029a526 100644
--- a/forge-gui/res/cardsfolder/t/tawnos_urzas_apprentice.txt
+++ b/forge-gui/res/cardsfolder/t/tawnos_urzas_apprentice.txt
@@ -3,5 +3,5 @@ ManaCost:U R
Types:Legendary Creature Human Artificer
PT:1/3
K:Haste
-A:AB$ CopySpellAbility | Cost$ U R T | TgtPrompt$ Select target activated or triggered ability you control from an artifact source | TargetType$ Activated.YouCtrl,Triggered.YouCtrl | ValidTgts$ Artifact | AILogic$ AlwaysCopyActivatedAbilities | StackDescription$ SpellDescription | SpellDescription$ Copy target activated or triggered ability you control from an artifact source. You may choose new targets for the copy. (Mana abilities can't be targeted.)
+A:AB$ CopySpellAbility | Cost$ U R T | TgtPrompt$ Select target activated or triggered ability you control from an artifact source | TargetType$ Activated.YouCtrl,Triggered.YouCtrl | ValidTgts$ Artifact | AILogic$ AlwaysCopyActivatedAbilities | MayChooseTarget$ True | StackDescription$ SpellDescription | SpellDescription$ Copy target activated or triggered ability you control from an artifact source. You may choose new targets for the copy. (Mana abilities can't be targeted.)
Oracle:Haste\n{U}{R}, {T}: Copy target activated or triggered ability you control from an artifact source. You may choose new targets for the copy. (Mana abilities can't be targeted.)
diff --git a/forge-gui/res/cardsfolder/t/the_mirari_conjecture.txt b/forge-gui/res/cardsfolder/t/the_mirari_conjecture.txt
index c43bdc70132..18b18155cae 100644
--- a/forge-gui/res/cardsfolder/t/the_mirari_conjecture.txt
+++ b/forge-gui/res/cardsfolder/t/the_mirari_conjecture.txt
@@ -6,7 +6,7 @@ SVar:DBChangeZoneI:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | Vali
SVar:DBChangeZoneII:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | ValidTgts$ Sorcery.YouCtrl | SpellDescription$ Return target sorcery card from your graveyard to your hand.
SVar:DBEffect:DB$ Effect | Name$ The Mirari Conjecture Effect | Triggers$ InstantSorceryCast | SVars$ TrigCopySpell | SpellDescription$ Until end of turn, whenever you cast an instant or sorcery spell, copy it. You may choose new targets for the copy.
SVar:InstantSorceryCast:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | Execute$ TrigCopySpell | TriggerZones$ Command | TriggerDescription$ Until end of turn, whenever you cast an instant or sorcery spell, copy it. You may choose new targets for the copy.
-SVar:TrigCopySpell:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility
+SVar:TrigCopySpell:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
SVar:NeedsToPlayVar:Z GE1
SVar:Z:Count$ValidGraveyard Instant.YouOwn,Sorcery.YouOwn
DeckHints:Type$Instant|Sorcery
diff --git a/forge-gui/res/cardsfolder/t/thousand_year_storm.txt b/forge-gui/res/cardsfolder/t/thousand_year_storm.txt
index e4425747b73..2f1701645e6 100644
--- a/forge-gui/res/cardsfolder/t/thousand_year_storm.txt
+++ b/forge-gui/res/cardsfolder/t/thousand_year_storm.txt
@@ -2,7 +2,7 @@ Name:Thousand-Year Storm
ManaCost:4 U R
Types:Enchantment
T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | Execute$ TrigCopy | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast an instant or sorcery spell, copy it for each other instant and sorcery spell you've cast before it this turn. You may choose new targets for the copies.
-SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ X | References$ X
+SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ X | References$ X | MayChooseTarget$ True
SVar:X:TriggerObjectsCurrentCastSpells$Valid Sorcery.YouCtrl,Instant.YouCtrl/Minus.1
DeckHints:Type$Instant|Sorcery
Oracle:Whenever you cast an instant or sorcery spell, copy it for each other instant and sorcery spell you've cast before it this turn. You may choose new targets for the copies.
diff --git a/forge-gui/res/cardsfolder/t/twincast.txt b/forge-gui/res/cardsfolder/t/twincast.txt
index a7f995a1afa..e219746f856 100644
--- a/forge-gui/res/cardsfolder/t/twincast.txt
+++ b/forge-gui/res/cardsfolder/t/twincast.txt
@@ -1,6 +1,5 @@
Name:Twincast
ManaCost:U U
Types:Instant
-A:SP$ CopySpellAbility | Cost$ U U | ValidTgts$ Instant,Sorcery | TargetType$ Spell | SpellDescription$ Copy target instant or sorcery spell. You may choose new targets for the copy.
-SVar:Picture:http://www.wizards.com/global/images/magic/general/twincast.jpg
+A:SP$ CopySpellAbility | Cost$ U U | ValidTgts$ Instant,Sorcery | TargetType$ Spell | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell. You may choose new targets for the copy.
Oracle:Copy target instant or sorcery spell. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/t/twinning_staff.txt b/forge-gui/res/cardsfolder/t/twinning_staff.txt
new file mode 100644
index 00000000000..5bc515dc796
--- /dev/null
+++ b/forge-gui/res/cardsfolder/t/twinning_staff.txt
@@ -0,0 +1,8 @@
+Name:Twinning Staff
+ManaCost:3
+Types:Artifact
+R:Event$ CopySpell | ActiveZones$ Battlefield | ValidPlayer$ You | ValidSpell$ Spell | ReplaceWith$ AddOneMore | Description$ If you would copy a spell one or more times, instead copy it that many times plus an additional time. You may choose new targets for the additional copy.
+SVar:AddOneMore:DB$ ReplaceEffect | VarName$ Amount | VarValue$ X | References$ X
+SVar:X:ReplaceCount$Amount/Plus.1
+A:AB$ CopySpellAbility | Cost$ 7 T | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | TargetType$ Spell | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell you control. You may choose new targets for the copy.
+Oracle:If you would copy a spell one or more times, instead copy it that many times plus an additional time. You may choose new targets for the additional copy.\n{7}, {T}: Copy target instant or sorcery spell you control. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/u/unbound_flourishing.txt b/forge-gui/res/cardsfolder/u/unbound_flourishing.txt
index da2350e6d30..f4fa0c35137 100644
--- a/forge-gui/res/cardsfolder/u/unbound_flourishing.txt
+++ b/forge-gui/res/cardsfolder/u/unbound_flourishing.txt
@@ -4,6 +4,6 @@ Types:Enchantment
T:Mode$ SpellCast | ValidCard$ Permanent | ValidActivatingPlayer$ You | Execute$ TrigDouble | TriggerZones$ Battlefield | HasXManaCost$ True | TriggerDescription$ Whenever you cast a permanent spell with a mana cost that contains X, double the value of X.
SVar:TrigDouble:DB$ ChangeX | Defined$ TriggeredStackInstance
T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | Execute$ TrigCopySpell | HasXManaCost$ True | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast an instant or sorcery spell or activate an ability, if that spell's mana cost or that ability's activation cost contains X, copy that spell or ability. You may choose new targets for the copy.
-SVar:TrigCopySpell:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | AILogic$ Always
+SVar:TrigCopySpell:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True | AILogic$ Always
T:Mode$ AbilityCast | HasXManaCost$ True | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigCopySpell | Secondary$ True | TriggerDescription$ Whenever you cast an instant or sorcery spell or activate an ability, if that spell's mana cost or that ability's activation cost contains X, copy that spell or ability. You may choose new targets for the copy.
Oracle:Whenever you cast a permanent spell with a mana cost that contains X, double the value of X.\nWhenever you cast an instant or sorcery spell or activate an ability, if that spell's mana cost or that ability's activation cost contains X, copy that spell or ability. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/u/uyo_silent_prophet.txt b/forge-gui/res/cardsfolder/u/uyo_silent_prophet.txt
index 9474f574879..4a55b2c8fcc 100644
--- a/forge-gui/res/cardsfolder/u/uyo_silent_prophet.txt
+++ b/forge-gui/res/cardsfolder/u/uyo_silent_prophet.txt
@@ -3,7 +3,6 @@ ManaCost:4 U U
Types:Legendary Creature Moonfolk Wizard
PT:4/4
K:Flying
-A:AB$CopySpellAbility | Cost$ 2 Return<2/Land> | ValidTgts$ Instant,Sorcery | SpellDescription$ Copy target instant or sorcery spell. You may choose new targets for the copy.
+A:AB$CopySpellAbility | Cost$ 2 Return<2/Land> | ValidTgts$ Instant,Sorcery | MayChooseTarget$ True | SpellDescription$ Copy target instant or sorcery spell. You may choose new targets for the copy.
AI:RemoveDeck:Random
-SVar:Picture:http://www.wizards.com/global/images/magic/general/uyo_silent_prophet.jpg
Oracle:Flying\n{2}, Return two lands you control to their owner's hand: Copy target instant or sorcery spell. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/v/verazol_the_split_current.txt b/forge-gui/res/cardsfolder/v/verazol_the_split_current.txt
new file mode 100644
index 00000000000..7c508de8bd2
--- /dev/null
+++ b/forge-gui/res/cardsfolder/v/verazol_the_split_current.txt
@@ -0,0 +1,15 @@
+Name:Verazol, the Split Current
+ManaCost:X G U
+Types:Legendary Creature Serpent
+PT:0/0
+K:etbCounter:P1P1:Y:no Condition:CARDNAME enters the battlefield with a +1/+1 counter on it for each mana spent to cast it.
+SVar:X:Count$xPaid
+SVar:Y:Count$FirstSpellTotalManaSpent
+T:Mode$ SpellCast | ValidSA$ Spell.Kicked | ValidActivatingPlayer$ You | Execute$ DBRemoveCounters | TriggerZones$ Battlefield | OptionalDecider$ You | TriggerDescription$ Whenever you cast a kicked spell, you may remove two +1/+1 counters from CARDNAME.
+SVar:DBRemoveCounters:DB$ RemoveCounter | CounterType$ P1P1 | CounterNum$ 2 | RememberRemoved$ True | SubAbility$ DBCopy
+SVar:DBCopy:DB$ CopySpellAbility | ConditionCheckSVar$ Z | ConditionSVarCompare$ GE1 | References$ Z | SubAbility$ DBCleanup | Defined$ TriggeredSpellAbility | AILogic$ Always | MayChooseTarget$ True | SpellDescription$ If you do, copy that spell. You may choose new targets for that copy. (A copy of a permanent spell becomes a token.)
+SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
+SVar:Z:Count$RememberedSize
+DeckHas:Ability$Counters
+Oracle:Verazol, the Split Current enters the battlefield with a +1/+1 counter on it for each mana spent to cast it.\nWhenever you cast a kicked spell, you may remove two +1/+1 counters from Verazol, the Split Current. If you do, copy that spell. You may choose new targets for that copy. (A copy of a permanent spell becomes a token.)
+
diff --git a/forge-gui/res/cardsfolder/w/wild_ricochet.txt b/forge-gui/res/cardsfolder/w/wild_ricochet.txt
index 0b584273e8e..2a40428f2ba 100644
--- a/forge-gui/res/cardsfolder/w/wild_ricochet.txt
+++ b/forge-gui/res/cardsfolder/w/wild_ricochet.txt
@@ -2,7 +2,6 @@ Name:Wild Ricochet
ManaCost:2 R R
Types:Instant
A:SP$ ChangeTargets | Cost$ 2 R R | TargetType$ Spell | Optional$ True | ValidTgts$ Instant,Sorcery | SubAbility$ DBCopy | SpellDescription$ You may choose new targets for target instant or sorcery spell. Then copy that spell. You may choose new targets for the copy.
-SVar:DBCopy:DB$ CopySpellAbility | Defined$ Targeted | Controller$ You
+SVar:DBCopy:DB$ CopySpellAbility | Defined$ Targeted | Controller$ You | MayChooseTarget$ True
AI:RemoveDeck:All
-SVar:Picture:http://www.wizards.com/global/images/magic/general/wild_ricochet.jpg
Oracle:You may choose new targets for target instant or sorcery spell. Then copy that spell. You may choose new targets for the copy.
diff --git a/forge-gui/res/cardsfolder/w/will_kenrith.txt b/forge-gui/res/cardsfolder/w/will_kenrith.txt
index 250aa84fe73..369d0b2b37b 100644
--- a/forge-gui/res/cardsfolder/w/will_kenrith.txt
+++ b/forge-gui/res/cardsfolder/w/will_kenrith.txt
@@ -10,6 +10,6 @@ SVar:DBEffect:DB$ Effect | StaticAbilities$ WillReduceCost | RememberObjects$ Ta
SVar:WillReduceCost:Mode$ ReduceCost | EffectZone$ Command | ValidCard$ Instant,Sorcery,Planeswalker | Type$ Spell | Activator$ Player.IsRemembered | Amount$ 2 | Description$ Until your next turn, instant, sorcery, and planeswalker spells that player casts cost {2} less to cast.
A:AB$ Effect | Cost$ SubCounter<8/LOYALTY> | Planeswalker$ True | Ultimate$ True | ValidTgts$ Player | EffectOwner$ Targeted | Name$ Emblem - Will Kenrith | Image$ emblem_will_kenrith | Triggers$ CopySpell | SVars$ TrigCopy | Duration$ Permanent | AILogic$ Always | SpellDescription$ Target player gets an emblem with "Whenever you cast an instant or sorcery spell, copy it. You may choose new targets for the copy."
SVar:CopySpell:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | Execute$ TrigCopy | TriggerZones$ Command | TriggerDescription$ Whenever you cast an instant or sorcery spell, copy it. You may choose new targets for the copy.
-SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility
+SVar:TrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
DeckHints:Name$Rowan Kenrith
Oracle:[+2]: Until your next turn, up to two target creatures each have base power and toughness 0/3 and lose all abilities.\n[-2]: Target player draws two cards. Until your next turn, instant, sorcery, and planeswalker spells that player casts cost {2} less to cast.\n[-8]: Target player gets an emblem with "Whenever you cast an instant or sorcery spell, copy it. You may choose new targets for the copy."\nPartner with Rowan Kenrith\nWill Kenrith can be your commander.
diff --git a/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java b/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java
index 649d023bdbb..c2a05dfc343 100644
--- a/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java
+++ b/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java
@@ -38,7 +38,6 @@ import forge.game.player.Player;
import forge.game.player.PlayerController;
import forge.game.spellability.*;
import forge.game.zone.Zone;
-import forge.util.collect.FCollection;
import org.apache.commons.lang3.StringUtils;
import java.util.Collections;
@@ -151,7 +150,7 @@ public class HumanPlaySpellAbility {
// is only executed or evaluated if the first argument does not suffice to determine the value of the expression
final boolean prerequisitesMet = announceValuesLikeX()
&& announceType()
- && (!mayChooseTargets || setupTargets()) // if you can choose targets, then do choose them.
+ && (!mayChooseTargets || ability.setupTargets()) // if you can choose targets, then do choose them.
&& (isFree || payment.payCost(new HumanCostDecision(controller, human, ability, ability.getHostCard())));
if (!prerequisitesMet) {
@@ -190,7 +189,7 @@ public class HumanPlaySpellAbility {
// no worries here. The same thread must resolve, and by this moment ability will have been resolved already
// Triggers haven't resolved yet ??
if (mayChooseTargets) {
- clearTargets(ability);
+ ability.clearTargets();
}
if (manaTypeConversion || manaColorConversion || keywordColor) {
manapool.restoreColorReplacements();
@@ -199,47 +198,6 @@ public class HumanPlaySpellAbility {
return true;
}
- private final boolean setupTargets() {
- // Skip to paying if parent ability doesn't target and has no subAbilities.
- // (or trigger case where its already targeted)
- SpellAbility currentAbility = ability;
- final Card source = ability.getHostCard();
- do {
- final TargetRestrictions tgt = currentAbility.getTargetRestrictions();
- if (tgt != null && tgt.doesTarget()) {
- clearTargets(currentAbility);
- Player targetingPlayer;
- if (currentAbility.hasParam("TargetingPlayer")) {
- final FCollection candidates = AbilityUtils.getDefinedPlayers(source, currentAbility.getParam("TargetingPlayer"), currentAbility);
- // activator chooses targeting player
- targetingPlayer = ability.getActivatingPlayer().getController().chooseSingleEntityForEffect(
- candidates, currentAbility, "Choose the targeting player", null);
- } else {
- targetingPlayer = ability.getActivatingPlayer();
- }
- currentAbility.setTargetingPlayer(targetingPlayer);
- if (!targetingPlayer.getController().chooseTargetsFor(currentAbility)) {
- return false;
- }
- }
- final AbilitySub subAbility = currentAbility.getSubAbility();
- if (subAbility != null) {
- // This is necessary for "TargetsWithDefinedController$ ParentTarget"
- subAbility.setParent(currentAbility);
- }
- currentAbility = subAbility;
- } while (currentAbility != null);
- return true;
- }
-
- public final void clearTargets(final SpellAbility ability) {
- final TargetRestrictions tg = ability.getTargetRestrictions();
- if (tg != null) {
- ability.resetTargets();
- tg.calculateStillToDivide(ability.getParam("DividedAsYouChoose"), ability.getHostCard(), ability);
- }
- }
-
private void rollbackAbility(final Zone fromZone, final int zonePosition, CostPayment payment) {
// cancel ability during target choosing
final Game game = ability.getActivatingPlayer().getGame();
@@ -251,7 +209,7 @@ public class HumanPlaySpellAbility {
game.getAction().moveTo(fromZone, ability.getHostCard(), zonePosition >= 0 ? Integer.valueOf(zonePosition) : null, null);
}
- clearTargets(ability);
+ ability.clearTargets();
ability.resetOnceResolved();
payment.refundPayment();
diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java
index 3469b1776ca..31f0b729c32 100644
--- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java
+++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java
@@ -1671,7 +1671,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
List orderedSAs = activePlayerSAs;
if (activePlayerSAs.size() > 1) {
final String firstStr = activePlayerSAs.get(0).toString();
- boolean needPrompt = false;
+ boolean needPrompt = !activePlayerSAs.get(0).isTrigger();
// for the purpose of pre-ordering, no need for extra granularity
Integer idxAdditionalInfo = firstStr.indexOf(" [");
@@ -1682,6 +1682,10 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
SpellAbility currentSa = activePlayerSAs.get(i);
String saStr = currentSa.toString();
+ // if current SA isn't a trigger and it uses Targeting, try to show prompt
+ if (!currentSa.isTrigger() && currentSa.usesTargeting()) {
+ needPrompt = true;
+ }
if (!needPrompt && !saStr.equals(firstStr)) {
needPrompt = true; // prompt by default unless all abilities
// are the same
@@ -1738,6 +1742,15 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
if (next.isTrigger()) {
HumanPlay.playSpellAbility(this, player, next);
} else {
+ if (next.isCopied()) {
+ // copied spell always add to stack
+ player.getGame().getStackZone().add(next.getHostCard());
+ // TODO check if static abilities needs to be run for things affecting the copy?
+ if (next.isMayChooseNewTargets() && !next.setupTargets()) {
+ // if targets can't be done, remove copy from existence
+ next.getHostCard().ceaseToExist();
+ }
+ }
player.getGame().getStack().add(next);
}
}