mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
Token table
This commit is contained in:
committed by
Michael Kamensky
parent
91d16eaa2d
commit
099970de6a
@@ -143,6 +143,7 @@ public enum SpellApiToAi {
|
||||
.put(ApiType.ReplaceEffect, AlwaysPlayAi.class)
|
||||
.put(ApiType.ReplaceDamage, AlwaysPlayAi.class)
|
||||
.put(ApiType.ReplaceSplitDamage, AlwaysPlayAi.class)
|
||||
.put(ApiType.ReplaceToken, AlwaysPlayAi.class)
|
||||
.put(ApiType.RestartGame, RestartGameAi.class)
|
||||
.put(ApiType.Reveal, RevealAi.class)
|
||||
.put(ApiType.RevealHand, RevealHandAi.class)
|
||||
|
||||
@@ -34,7 +34,7 @@ public class AmassAi extends SpellAbilityAi {
|
||||
final String tokenScript = "b_0_0_zombie_army";
|
||||
final int amount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Num", "1"), sa);
|
||||
|
||||
Card token = TokenInfo.getProtoType(tokenScript, sa, false);
|
||||
Card token = TokenInfo.getProtoType(tokenScript, sa, ai, false);
|
||||
|
||||
if (token == null) {
|
||||
return false;
|
||||
|
||||
@@ -358,7 +358,7 @@ public class TokenAi extends SpellAbilityAi {
|
||||
if (!sa.hasParam("TokenScript")) {
|
||||
throw new RuntimeException("Spell Ability has no TokenScript: " + sa);
|
||||
}
|
||||
Card result = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa);
|
||||
Card result = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa, ai);
|
||||
|
||||
if (result == null) {
|
||||
throw new RuntimeException("don't find Token for TokenScript: " + sa.getParam("TokenScript"));
|
||||
|
||||
@@ -142,6 +142,7 @@ public enum ApiType {
|
||||
ReplaceEffect (ReplaceEffect.class),
|
||||
ReplaceMana (ReplaceManaEffect.class),
|
||||
ReplaceDamage (ReplaceDamageEffect.class),
|
||||
ReplaceToken (ReplaceTokenEffect.class),
|
||||
ReplaceSplitDamage (ReplaceSplitDamageEffect.class),
|
||||
RestartGame (RestartGameEffect.class),
|
||||
Reveal (RevealEffect.class),
|
||||
|
||||
@@ -16,7 +16,6 @@ import forge.game.card.CardPredicates;
|
||||
import forge.game.card.CardZoneTable;
|
||||
import forge.game.card.CounterEnumType;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.card.token.TokenInfo;
|
||||
import forge.game.event.GameEventCombatChanged;
|
||||
import forge.game.event.GameEventTokenCreated;
|
||||
import forge.game.player.Player;
|
||||
@@ -53,37 +52,24 @@ public class AmassEffect extends TokenEffectBase {
|
||||
final int amount = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("Num", "1"), sa);
|
||||
final boolean remember = sa.hasParam("RememberAmass");
|
||||
|
||||
boolean useZoneTable = true;
|
||||
CardZoneTable triggerList = sa.getChangeZoneTable();
|
||||
if (triggerList == null) {
|
||||
triggerList = new CardZoneTable();
|
||||
useZoneTable = false;
|
||||
}
|
||||
if (sa.hasParam("ChangeZoneTable")) {
|
||||
sa.setChangeZoneTable(triggerList);
|
||||
useZoneTable = true;
|
||||
}
|
||||
|
||||
MutableBoolean combatChanged = new MutableBoolean(false);
|
||||
// create army token if needed
|
||||
if (CardLists.count(activator.getCardsIn(ZoneType.Battlefield), CardPredicates.isType("Army")) == 0) {
|
||||
final String tokenScript = "b_0_0_zombie_army";
|
||||
CardZoneTable triggerList = new CardZoneTable();
|
||||
MutableBoolean combatChanged = new MutableBoolean(false);
|
||||
|
||||
final Card prototype = TokenInfo.getProtoType(tokenScript, sa, false);
|
||||
makeTokenTable(makeTokenTableInternal(activator, "b_0_0_zombie_army", 1, sa), false, triggerList, combatChanged, sa);
|
||||
|
||||
makeTokens(prototype, activator, sa, 1, true, false, triggerList, combatChanged);
|
||||
|
||||
if (!useZoneTable) {
|
||||
triggerList.triggerChangesZoneAll(game, sa);
|
||||
triggerList.clear();
|
||||
}
|
||||
|
||||
game.fireEvent(new GameEventTokenCreated());
|
||||
}
|
||||
|
||||
if (combatChanged.isTrue()) {
|
||||
game.updateCombatForView();
|
||||
game.fireEvent(new GameEventCombatChanged());
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> params = Maps.newHashMap();
|
||||
params.put("CounterType", CounterType.get(CounterEnumType.P1P1));
|
||||
params.put("Amount", 1);
|
||||
|
||||
@@ -20,6 +20,7 @@ import forge.game.card.CardFactory;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.card.CardPredicates;
|
||||
import forge.game.card.CardZoneTable;
|
||||
import forge.game.card.TokenCreateTable;
|
||||
import forge.game.event.GameEventCombatChanged;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerActionConfirmMode;
|
||||
@@ -177,15 +178,18 @@ public class CopyPermanentEffect extends TokenEffectBase {
|
||||
}
|
||||
|
||||
MutableBoolean combatChanged = new MutableBoolean(false);
|
||||
TokenCreateTable tokenTable = new TokenCreateTable();
|
||||
|
||||
for (final Card c : tgtCards) {
|
||||
// if it only targets player, it already got all needed cards from defined
|
||||
if (sa.usesTargeting() && !sa.getTargetRestrictions().canTgtPlayer() && !c.canBeTargetedBy(sa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
makeTokens(getProtoType(sa, c), controller, sa, numCopies, true, true, triggerList, combatChanged);
|
||||
tokenTable.put(controller, getProtoType(sa, c, controller), numCopies);
|
||||
} // end foreach Card
|
||||
|
||||
makeTokenTable(tokenTable, true, triggerList, combatChanged, sa);
|
||||
|
||||
if (!useZoneTable) {
|
||||
triggerList.triggerChangesZoneAll(game, sa);
|
||||
triggerList.clear();
|
||||
@@ -196,9 +200,8 @@ public class CopyPermanentEffect extends TokenEffectBase {
|
||||
}
|
||||
} // end resolve
|
||||
|
||||
private Card getProtoType(final SpellAbility sa, final Card original) {
|
||||
private Card getProtoType(final SpellAbility sa, final Card original, final Player newOwner) {
|
||||
final Card host = sa.getHostCard();
|
||||
final Player newOwner = sa.getActivatingPlayer();
|
||||
int id = newOwner == null ? 0 : newOwner.getGame().nextCardId();
|
||||
final Card copy = new Card(id, original.getPaperCard(), host.getGame());
|
||||
copy.setOwner(newOwner);
|
||||
|
||||
@@ -6,7 +6,6 @@ import forge.game.Game;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardZoneTable;
|
||||
import forge.game.card.token.TokenInfo;
|
||||
import forge.game.event.GameEventCombatChanged;
|
||||
import forge.game.event.GameEventTokenCreated;
|
||||
import forge.game.player.Player;
|
||||
@@ -36,14 +35,13 @@ public class InvestigateEffect extends TokenEffectBase {
|
||||
|
||||
final int amount = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("Num", "1"), sa);
|
||||
|
||||
final String tokenScript = "c_a_clue_draw";
|
||||
final Card prototype = TokenInfo.getProtoType(tokenScript, sa, false);
|
||||
|
||||
// Investigate in Sequence
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
for (int i = 0; i < amount; i++) {
|
||||
CardZoneTable triggerList = new CardZoneTable();
|
||||
MutableBoolean combatChanged = new MutableBoolean(false);
|
||||
makeTokens(prototype, p, sa, 1, true, false, triggerList, combatChanged);
|
||||
|
||||
makeTokenTable(makeTokenTableInternal(p, "c_a_clue_draw", 1, sa), false, triggerList, combatChanged, sa);
|
||||
|
||||
triggerList.triggerChangesZoneAll(game, sa);
|
||||
p.addInvestigatedThisTurn();
|
||||
|
||||
@@ -3,12 +3,6 @@ package forge.game.ability.effects;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.GameLogEntryType;
|
||||
import forge.game.GameObject;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
@@ -17,25 +11,21 @@ import forge.game.card.Card;
|
||||
import forge.game.card.token.TokenInfo;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.replacement.ReplacementResult;
|
||||
import forge.game.replacement.ReplacementType;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
|
||||
public class ReplaceEffect extends SpellAbilityEffect {
|
||||
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
final Card card = sa.getHostCard();
|
||||
final Game game = card.getGame();
|
||||
|
||||
final AbilityKey varName = AbilityKey.fromString(sa.getParam("VarName"));
|
||||
final String varValue = sa.getParam("VarValue");
|
||||
final String type = sa.getParamOrDefault("VarType", "amount");
|
||||
final ReplacementType retype = sa.getReplacementEffect().getMode();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<AbilityKey, Object> originalParams = (Map<AbilityKey, Object>) sa.getReplacingObject(AbilityKey.OriginalParams);
|
||||
Map<AbilityKey, Object> params = Maps.newHashMap(originalParams);
|
||||
Map<AbilityKey, Object> params = (Map<AbilityKey, Object>) sa.getReplacingObject(AbilityKey.OriginalParams);
|
||||
|
||||
if ("Card".equals(type)) {
|
||||
List<Card> list = AbilityUtils.getDefinedCards(card, varValue, sa);
|
||||
@@ -53,7 +43,7 @@ public class ReplaceEffect extends SpellAbilityEffect {
|
||||
params.put(varName, list.get(0));
|
||||
}
|
||||
} else if ("TokenScript".equals(type)) {
|
||||
final Card protoType = TokenInfo.getProtoType(varValue, sa);
|
||||
final Card protoType = TokenInfo.getProtoType(varValue, sa, sa.getActivatingPlayer());
|
||||
if (protoType != null) {
|
||||
params.put(varName, protoType);
|
||||
}
|
||||
@@ -61,42 +51,7 @@ public class ReplaceEffect extends SpellAbilityEffect {
|
||||
params.put(varName, AbilityUtils.calculateAmount(card, varValue, sa));
|
||||
}
|
||||
|
||||
if (params.containsKey(AbilityKey.EffectOnly)) {
|
||||
params.put(AbilityKey.EffectOnly, true);
|
||||
}
|
||||
|
||||
if (retype == ReplacementType.DamageDone) {
|
||||
for (Map.Entry<AbilityKey, Object> e : params.entrySet()) {
|
||||
originalParams.put(e.getKey(), e.getValue());
|
||||
}
|
||||
originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
|
||||
return;
|
||||
}
|
||||
|
||||
// need to log Updated events there, or the log is wrong order
|
||||
String message = sa.getReplacementEffect().toString();
|
||||
if ( !StringUtils.isEmpty(message)) {
|
||||
message = TextUtil.fastReplace(message, "CARDNAME", card.getName());
|
||||
game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message);
|
||||
}
|
||||
|
||||
//try to call replacementHandler with new Params
|
||||
ReplacementResult result = game.getReplacementHandler().run(retype, params);
|
||||
switch (result) {
|
||||
case NotReplaced:
|
||||
case Updated: {
|
||||
for (Map.Entry<AbilityKey, Object> e : params.entrySet()) {
|
||||
originalParams.put(e.getKey(), e.getValue());
|
||||
}
|
||||
// effect was updated
|
||||
originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// effect was replaced with something else
|
||||
originalParams.put(AbilityKey.ReplacementResult, result);
|
||||
break;
|
||||
}
|
||||
params.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,20 +4,15 @@ import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.MagicColor;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameLogEntryType;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.replacement.ReplacementResult;
|
||||
import forge.game.replacement.ReplacementType;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
public class ReplaceManaEffect extends SpellAbilityEffect {
|
||||
|
||||
@@ -25,17 +20,14 @@ public class ReplaceManaEffect extends SpellAbilityEffect {
|
||||
public void resolve(SpellAbility sa) {
|
||||
final Card card = sa.getHostCard();
|
||||
final Player player = sa.getActivatingPlayer();
|
||||
final Game game = card.getGame();
|
||||
|
||||
// outside of Replacement Effect, unwanted result
|
||||
if (!sa.isReplacementAbility()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ReplacementType event = sa.getReplacementEffect().getMode();
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<AbilityKey, Object> originalParams = (Map<AbilityKey, Object>) sa.getReplacingObject(AbilityKey.OriginalParams);
|
||||
Map<AbilityKey, Object> params = Maps.newHashMap(originalParams);
|
||||
Map<AbilityKey, Object> params = (Map<AbilityKey, Object>) sa.getReplacingObject(AbilityKey.OriginalParams);
|
||||
|
||||
String replaced = (String)sa.getReplacingObject(AbilityKey.Mana);
|
||||
if (sa.hasParam("ReplaceMana")) {
|
||||
@@ -79,31 +71,8 @@ public class ReplaceManaEffect extends SpellAbilityEffect {
|
||||
replaced = StringUtils.repeat(replaced, " ", Integer.valueOf(sa.getParam("ReplaceAmount")));
|
||||
}
|
||||
params.put(AbilityKey.Mana, replaced);
|
||||
|
||||
// need to log Updated events there, or the log is wrong order
|
||||
String message = sa.getReplacementEffect().toString();
|
||||
if (!StringUtils.isEmpty(message)) {
|
||||
message = TextUtil.fastReplace(message, "CARDNAME", card.getName());
|
||||
game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message);
|
||||
}
|
||||
|
||||
//try to call replacementHandler with new Params
|
||||
ReplacementResult result = game.getReplacementHandler().run(event, params);
|
||||
switch (result) {
|
||||
case NotReplaced:
|
||||
case Updated: {
|
||||
for (Map.Entry<AbilityKey, Object> e : params.entrySet()) {
|
||||
originalParams.put(e.getKey(), e.getValue());
|
||||
}
|
||||
// effect was updated
|
||||
originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// effect was replaced with something else
|
||||
originalParams.put(AbilityKey.ReplacementResult, result);
|
||||
break;
|
||||
}
|
||||
params.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.TokenCreateTable;
|
||||
import forge.game.card.token.TokenInfo;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.replacement.ReplacementResult;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
|
||||
public class ReplaceTokenEffect extends SpellAbilityEffect {
|
||||
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
final Card card = sa.getHostCard();
|
||||
final Player p = sa.getActivatingPlayer();
|
||||
final Game game = card.getGame();
|
||||
|
||||
// ReplaceToken Effect only applies to one Player
|
||||
Player affected = (Player) sa.getReplacingObject(AbilityKey.Player);
|
||||
TokenCreateTable table = (TokenCreateTable) sa.getReplacingObject(AbilityKey.Token);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<AbilityKey, Object> originalParams = (Map<AbilityKey, Object>) sa
|
||||
.getReplacingObject(AbilityKey.OriginalParams);
|
||||
|
||||
// currently the only ones that changes the amount does double it
|
||||
if ("Amount".equals(sa.getParam("Type"))) {
|
||||
for (Map.Entry<Card, Integer> e : table.row(affected).entrySet()) {
|
||||
if (!sa.matchesValidParam("ValidCard", e.getKey())) {
|
||||
continue;
|
||||
}
|
||||
// currently the amount is only doubled
|
||||
table.put(affected, e.getKey(), e.getValue() * 2);
|
||||
}
|
||||
} else if ("AddToken".equals(sa.getParam("Type"))) {
|
||||
long timestamp = game.getNextTimestamp();
|
||||
|
||||
Map<Player, Integer> byController = Maps.newHashMap();
|
||||
for (Map.Entry<Card, Integer> e : table.row(affected).entrySet()) {
|
||||
if (!sa.matchesValidParam("ValidCard", e.getKey())) {
|
||||
continue;
|
||||
}
|
||||
Player contoller = e.getKey().getController();
|
||||
int old = ObjectUtils.defaultIfNull(byController.get(contoller), 0);
|
||||
byController.put(contoller, old + e.getValue());
|
||||
}
|
||||
|
||||
if (!byController.isEmpty()) {
|
||||
// for Xorn, might matter if you could somehow create Treasure under multiple players control
|
||||
if (sa.hasParam("Amount")) {
|
||||
int i = AbilityUtils.calculateAmount(card, sa.getParam("Amount"), sa);
|
||||
for (Map.Entry<Player, Integer> e : byController.entrySet()) {
|
||||
e.setValue(i);
|
||||
}
|
||||
}
|
||||
for (Map.Entry<Player, Integer> e : byController.entrySet()) {
|
||||
for (String script : sa.getParam("TokenScript").split(",")) {
|
||||
final Card token = TokenInfo.getProtoType(script, sa, p);
|
||||
|
||||
if (token == null) {
|
||||
throw new RuntimeException("don't find Token for TokenScript: " + script);
|
||||
}
|
||||
token.setController(e.getKey(), timestamp);
|
||||
table.put(p, token, e.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ("ReplaceToken".equals(sa.getParam("Type"))) {
|
||||
long timestamp = game.getNextTimestamp();
|
||||
|
||||
Map<Player, Integer> toInsertMap = Maps.newHashMap();
|
||||
Set<Card> toRemoveSet = Sets.newHashSet();
|
||||
for (Map.Entry<Card, Integer> e : table.row(affected).entrySet()) {
|
||||
if (!sa.matchesValidParam("ValidCard", e.getKey())) {
|
||||
continue;
|
||||
}
|
||||
Player controller = e.getKey().getController();
|
||||
int old = ObjectUtils.defaultIfNull(toInsertMap.get(controller), 0);
|
||||
toInsertMap.put(controller, old + e.getValue());
|
||||
toRemoveSet.add(e.getKey());
|
||||
}
|
||||
// remove replaced tokens
|
||||
table.row(affected).keySet().removeAll(toRemoveSet);
|
||||
|
||||
// insert new tokens
|
||||
for (Map.Entry<Player, Integer> pe : toInsertMap.entrySet()) {
|
||||
if (pe.getValue() <= 0) {
|
||||
continue;
|
||||
}
|
||||
for (String script : sa.getParam("TokenScript").split(",")) {
|
||||
final Card token = TokenInfo.getProtoType(script, sa, pe.getKey());
|
||||
|
||||
if (token == null) {
|
||||
throw new RuntimeException("don't find Token for TokenScript: " + script);
|
||||
}
|
||||
|
||||
token.setController(pe.getKey(), timestamp);
|
||||
table.put(affected, token, pe.getValue());
|
||||
}
|
||||
}
|
||||
} else if ("ReplaceController".equals(sa.getParam("Type"))) {
|
||||
long timestamp = game.getNextTimestamp();
|
||||
Player newController = sa.getActivatingPlayer();
|
||||
if (sa.hasParam("NewController")) {
|
||||
newController = AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("NewController"), sa).get(0);
|
||||
}
|
||||
for (Map.Entry<Card, Integer> c : table.row(affected).entrySet()) {
|
||||
if (!sa.matchesValidParam("ValidCard", c.getKey())) {
|
||||
continue;
|
||||
}
|
||||
c.getKey().setController(newController, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
// effect was updated
|
||||
originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,10 +23,8 @@ import forge.game.Game;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardZoneTable;
|
||||
import forge.game.card.token.TokenInfo;
|
||||
import forge.game.event.GameEventCombatChanged;
|
||||
import forge.game.event.GameEventTokenCreated;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
|
||||
public class TokenEffect extends TokenEffectBase {
|
||||
@@ -36,20 +34,6 @@ public class TokenEffect extends TokenEffectBase {
|
||||
return sa.getDescription();
|
||||
}
|
||||
|
||||
public Card loadTokenPrototype(SpellAbility sa) {
|
||||
if (!sa.hasParam("TokenScript")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Card result = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa);
|
||||
|
||||
if (result == null) {
|
||||
throw new RuntimeException("don't find Token for TokenScript: " + sa.getParam("TokenScript"));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
final Card host = sa.getHostCard();
|
||||
@@ -67,9 +51,8 @@ public class TokenEffect extends TokenEffectBase {
|
||||
}
|
||||
}
|
||||
|
||||
Card prototype = loadTokenPrototype(sa);
|
||||
|
||||
final int finalAmount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("TokenAmount", "1"), sa);
|
||||
MutableBoolean combatChanged = new MutableBoolean(false);
|
||||
|
||||
boolean useZoneTable = true;
|
||||
CardZoneTable triggerList = sa.getChangeZoneTable();
|
||||
@@ -82,10 +65,8 @@ public class TokenEffect extends TokenEffectBase {
|
||||
useZoneTable = true;
|
||||
}
|
||||
|
||||
MutableBoolean combatChanged = new MutableBoolean(false);
|
||||
for (final Player owner : AbilityUtils.getDefinedPlayers(host, sa.getParamOrDefault("TokenOwner", "You"), sa)) {
|
||||
makeTokens(prototype, owner, sa, finalAmount, true, false, triggerList, combatChanged);
|
||||
}
|
||||
makeTokenTable(AbilityUtils.getDefinedPlayers(host, sa.getParamOrDefault("TokenOwner", "You"), sa),
|
||||
sa.getParam("TokenScript").split(","), finalAmount, false, triggerList, combatChanged, sa);
|
||||
|
||||
if (!useZoneTable) {
|
||||
triggerList.triggerChangesZoneAll(game, sa);
|
||||
|
||||
@@ -2,45 +2,124 @@ package forge.game.ability.effects;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Table;
|
||||
|
||||
import forge.GameCommand;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.GameObject;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardFactory;
|
||||
import forge.game.card.CardUtil;
|
||||
import forge.game.card.CardZoneTable;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.card.TokenCreateTable;
|
||||
import forge.game.card.token.TokenInfo;
|
||||
import forge.game.event.GameEventCardStatsChanged;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.replacement.ReplacementType;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.zone.ZoneType;
|
||||
|
||||
public abstract class TokenEffectBase extends SpellAbilityEffect {
|
||||
|
||||
protected List<Card> makeTokens(final Card prototype, final Player creator, final SpellAbility sa, int finalAmount,
|
||||
boolean applyMultiplier, boolean clone, CardZoneTable triggerList, MutableBoolean combatChanged) {
|
||||
protected TokenCreateTable createTokenTable(Iterable<Player> players, String[] tokenScripts, final int finalAmount, final SpellAbility sa) {
|
||||
|
||||
TokenCreateTable tokenTable = new TokenCreateTable();
|
||||
for (final Player owner : players) {
|
||||
for (String script : tokenScripts) {
|
||||
final Card result = TokenInfo.getProtoType(script, sa, owner);
|
||||
|
||||
if (result == null) {
|
||||
throw new RuntimeException("don't find Token for TokenScript: " + script);
|
||||
}
|
||||
// set owner
|
||||
result.setOwner(owner);
|
||||
tokenTable.put(owner, result, finalAmount);
|
||||
}
|
||||
}
|
||||
return tokenTable;
|
||||
}
|
||||
|
||||
protected TokenCreateTable makeTokenTableInternal(Player owner, String script, final int finalAmount, final SpellAbility sa) {
|
||||
TokenCreateTable tokenTable = new TokenCreateTable();
|
||||
final Card result = TokenInfo.getProtoType(script, sa, owner, false);
|
||||
|
||||
if (result == null) {
|
||||
throw new RuntimeException("don't find Token for TokenScript: " + script);
|
||||
}
|
||||
// set owner
|
||||
result.setOwner(owner);
|
||||
tokenTable.put(owner, result, finalAmount);
|
||||
|
||||
return tokenTable;
|
||||
}
|
||||
|
||||
protected TokenCreateTable makeTokenTable(Iterable<Player> players, String[] tokenScripts, final int finalAmount, final boolean clone,
|
||||
CardZoneTable triggerList, MutableBoolean combatChanged, final SpellAbility sa) {
|
||||
return makeTokenTable(createTokenTable(players, tokenScripts, finalAmount, sa), clone, triggerList, combatChanged, sa);
|
||||
}
|
||||
|
||||
protected TokenCreateTable makeTokenTable(TokenCreateTable tokenTable, final boolean clone, CardZoneTable triggerList, MutableBoolean combatChanged, final SpellAbility sa) {
|
||||
final Card host = sa.getHostCard();
|
||||
final Game game = host.getGame();
|
||||
final long timestamp = game.getNextTimestamp();
|
||||
long timestamp = game.getNextTimestamp();
|
||||
|
||||
// support PlayerCollection for affected
|
||||
Set<Player> toRemove = Sets.newHashSet();
|
||||
for (Player p : tokenTable.rowKeySet()) {
|
||||
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(p);
|
||||
repParams.put(AbilityKey.Token, tokenTable);
|
||||
repParams.put(AbilityKey.EffectOnly, true); // currently only effects can create tokens?
|
||||
|
||||
switch (game.getReplacementHandler().run(ReplacementType.CreateToken, repParams)) {
|
||||
case NotReplaced:
|
||||
break;
|
||||
case Updated: {
|
||||
tokenTable = (TokenCreateTable) repParams.get(AbilityKey.Token);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
toRemove.add(p);
|
||||
}
|
||||
}
|
||||
tokenTable.rowKeySet().removeAll(toRemove);
|
||||
|
||||
final List<String> pumpKeywords = Lists.newArrayList();
|
||||
if (sa.hasParam("PumpKeywords")) {
|
||||
pumpKeywords.addAll(Arrays.asList(sa.getParam("PumpKeywords").split(" & ")));
|
||||
}
|
||||
|
||||
List<Card> allTokens = Lists.newArrayList();
|
||||
for (Card tok : TokenInfo.makeTokensFromPrototype(prototype, creator, finalAmount, applyMultiplier)) {
|
||||
for (final Table.Cell<Player, Card, Integer> c : tokenTable.cellSet()) {
|
||||
Card prototype = c.getColumnKey();
|
||||
Player creator = c.getRowKey();
|
||||
Player controller = prototype.getController();
|
||||
int cellAmount = c.getValue();
|
||||
for (int i = 0; i < cellAmount; i++) {
|
||||
Card tok = CardFactory.copyCard(prototype, true);
|
||||
// Crafty Cutpurse would change under which control it does enter,
|
||||
// but it shouldn't change who creates the token
|
||||
tok.setOwner(creator);
|
||||
if (creator != controller) {
|
||||
tok.setController(controller, timestamp);
|
||||
}
|
||||
tok.setTimestamp(timestamp);
|
||||
tok.setToken(true);
|
||||
|
||||
// do effect stuff with the token
|
||||
if (sa.hasParam("TokenTapped")) {
|
||||
tok.setTapped(true);
|
||||
}
|
||||
@@ -48,7 +127,6 @@ public abstract class TokenEffectBase extends SpellAbilityEffect {
|
||||
if (!sa.hasParam("AttachAfter") && sa.hasParam("AttachedTo") && !attachTokenTo(tok, sa)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sa.hasParam("WithCounters")) {
|
||||
String[] parse = sa.getParam("WithCounters").split("_");
|
||||
tok.addEtbCounter(CounterType.getType(parse[0]), Integer.parseInt(parse[1]), creator);
|
||||
@@ -65,29 +143,29 @@ public abstract class TokenEffectBase extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
// Should this be catching the Card that's returned?
|
||||
Card c = game.getAction().moveToPlay(tok, sa);
|
||||
if (c == null || c.getZone() == null) {
|
||||
Card moved = game.getAction().moveToPlay(tok, sa);
|
||||
if (moved == null || moved.getZone() == null) {
|
||||
// in case token can't enter the battlefield, it isn't created
|
||||
triggerList.put(ZoneType.None, ZoneType.None, c);
|
||||
triggerList.put(ZoneType.None, ZoneType.None, moved);
|
||||
continue;
|
||||
}
|
||||
triggerList.put(ZoneType.None, c.getZone().getZoneType(), c);
|
||||
triggerList.put(ZoneType.None, moved.getZone().getZoneType(), moved);
|
||||
|
||||
creator.addTokensCreatedThisTurn();
|
||||
|
||||
if (clone) {
|
||||
c.setCloneOrigin(host);
|
||||
moved.setCloneOrigin(host);
|
||||
}
|
||||
if (!pumpKeywords.isEmpty()) {
|
||||
c.addChangedCardKeywords(pumpKeywords, Lists.newArrayList(), false, false, timestamp);
|
||||
addPumpUntil(sa, c, timestamp);
|
||||
moved.addChangedCardKeywords(pumpKeywords, Lists.newArrayList(), false, false, timestamp);
|
||||
addPumpUntil(sa, moved, timestamp);
|
||||
}
|
||||
|
||||
if (sa.hasParam("AtEOTTrig")) {
|
||||
addSelfTrigger(sa, sa.getParam("AtEOTTrig"), c);
|
||||
addSelfTrigger(sa, sa.getParam("AtEOTTrig"), moved);
|
||||
}
|
||||
|
||||
if (addToCombat(c, tok.getController(), sa, "TokenAttacking", "TokenBlocking")) {
|
||||
if (addToCombat(moved, tok.getController(), sa, "TokenAttacking", "TokenBlocking")) {
|
||||
combatChanged.setTrue();
|
||||
}
|
||||
|
||||
@@ -95,30 +173,31 @@ public abstract class TokenEffectBase extends SpellAbilityEffect {
|
||||
attachTokenTo(tok, sa);
|
||||
}
|
||||
|
||||
c.updateStateForView();
|
||||
moved.updateStateForView();
|
||||
|
||||
if (sa.hasParam("RememberTokens")) {
|
||||
host.addRemembered(c);
|
||||
host.addRemembered(moved);
|
||||
}
|
||||
if (sa.hasParam("ImprintTokens")) {
|
||||
host.addImprintedCard(c);
|
||||
host.addImprintedCard(moved);
|
||||
}
|
||||
if (sa.hasParam("RememberSource")) {
|
||||
c.addRemembered(host);
|
||||
moved.addRemembered(host);
|
||||
}
|
||||
if (sa.hasParam("TokenRemembered")) {
|
||||
final String remembered = sa.getParam("TokenRemembered");
|
||||
for (final Object o : AbilityUtils.getDefinedObjects(host, remembered, sa)) {
|
||||
c.addRemembered(o);
|
||||
moved.addRemembered(o);
|
||||
}
|
||||
}
|
||||
allTokens.add(c);
|
||||
allTokens.add(moved);
|
||||
}
|
||||
}
|
||||
|
||||
if (sa.hasParam("AtEOT")) {
|
||||
registerDelayedTrigger(sa, sa.getParam("AtEOT"), allTokens);
|
||||
}
|
||||
return allTokens;
|
||||
return tokenTable;
|
||||
}
|
||||
|
||||
private boolean attachTokenTo(Card tok, SpellAbility sa) {
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package forge.game.card;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
||||
import com.google.common.collect.ForwardingTable;
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Table;
|
||||
|
||||
import forge.game.CardTraitBase;
|
||||
import forge.game.GameObjectPredicates;
|
||||
import forge.game.player.Player;
|
||||
|
||||
public class TokenCreateTable extends ForwardingTable<Player, Card, Integer> {
|
||||
|
||||
Table<Player, Card, Integer> dataMap = HashBasedTable.create();
|
||||
|
||||
public TokenCreateTable() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Table<Player, Card, Integer> delegate() {
|
||||
return dataMap;
|
||||
}
|
||||
|
||||
public int add(Player p, Card c, int i) {
|
||||
int old = ObjectUtils.defaultIfNull(this.get(p, c), 0);
|
||||
int newValue = old + i;
|
||||
this.put(p, c, newValue);
|
||||
return newValue;
|
||||
}
|
||||
|
||||
public int getFilterAmount(String validOwner, String validToken, final CardTraitBase ctb) {
|
||||
final Card host = ctb.getHostCard();
|
||||
int result = 0;
|
||||
List<Card> filteredCards = null;
|
||||
List<Player> filteredPlayer = null;
|
||||
|
||||
if (validOwner == null && validToken == null) {
|
||||
for (Integer i : values()) {
|
||||
result += i;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if (validOwner != null) {
|
||||
filteredPlayer = Lists.newArrayList(Iterables.filter(rowKeySet(),
|
||||
GameObjectPredicates.restriction(validOwner.split(","), host.getController(), host, ctb)));
|
||||
if (filteredPlayer.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (validToken != null) {
|
||||
filteredCards = CardLists.getValidCardsAsList(columnKeySet(), validToken, host.getController(), host, ctb);
|
||||
if (filteredCards.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (filteredPlayer == null) {
|
||||
for (Map.Entry<Card, Map<Player, Integer>> e : columnMap().entrySet()) {
|
||||
for (Integer i : e.getValue().values()) {
|
||||
result += i;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if (filteredCards == null) {
|
||||
for (Map.Entry<Player, Map<Card, Integer>> e : rowMap().entrySet()) {
|
||||
for (Integer i : e.getValue().values()) {
|
||||
result += i;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
for (Table.Cell<Player, Card, Integer> c : this.cellSet()) {
|
||||
if (!filteredPlayer.contains(c.getRowKey())) {
|
||||
continue;
|
||||
}
|
||||
if (!filteredCards.contains(c.getColumnKey())) {
|
||||
continue;
|
||||
}
|
||||
result += c.getValue();
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -15,15 +15,12 @@ import forge.StaticData;
|
||||
import forge.card.CardType;
|
||||
import forge.card.MagicColor;
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardFactory;
|
||||
import forge.game.card.CardFactoryUtil;
|
||||
import forge.game.card.CardUtil;
|
||||
import forge.game.keyword.KeywordInterface;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.replacement.ReplacementType;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.item.PaperToken;
|
||||
|
||||
@@ -140,59 +137,6 @@ public class TokenInfo {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static List<Card> makeToken(final Card prototype, final Player owner,
|
||||
final boolean applyMultiplier, final int num) {
|
||||
final List<Card> list = Lists.newArrayList();
|
||||
|
||||
final Game game = owner.getGame();
|
||||
int multiplier = num;
|
||||
Player player = owner;
|
||||
Card proto = prototype;
|
||||
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(player);
|
||||
repParams.put(AbilityKey.Token, prototype);
|
||||
repParams.put(AbilityKey.TokenNum, multiplier);
|
||||
repParams.put(AbilityKey.EffectOnly, applyMultiplier);
|
||||
|
||||
switch (game.getReplacementHandler().run(ReplacementType.CreateToken, repParams)) {
|
||||
case NotReplaced:
|
||||
break;
|
||||
case Updated: {
|
||||
multiplier = (int) repParams.get(AbilityKey.TokenNum);
|
||||
player = (Player) repParams.get(AbilityKey.Affected);
|
||||
proto = (Card) repParams.get(AbilityKey.Token);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
multiplier = 0;
|
||||
break;
|
||||
}
|
||||
if (multiplier <= 0) {
|
||||
return list;
|
||||
}
|
||||
|
||||
long timestamp = game.getNextTimestamp();
|
||||
|
||||
for (int i = 0; i < multiplier; i++) {
|
||||
// need to set owner or copyCard will fail with assign new ID
|
||||
proto.setOwner(owner);
|
||||
Card copy = CardFactory.copyCard(proto, true);
|
||||
// need to assign player after token is copied
|
||||
if (player != owner) {
|
||||
copy.setController(player, timestamp);
|
||||
}
|
||||
copy.setTimestamp(timestamp);
|
||||
copy.setToken(true);
|
||||
list.add(copy);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static public List<Card> makeTokensFromPrototype(Card prototype, final Player owner, int amount, final boolean applyMultiplier) {
|
||||
return makeToken(prototype, owner, applyMultiplier, amount);
|
||||
}
|
||||
|
||||
public Card makeOneToken(final Player controller) {
|
||||
final Game game = controller.getGame();
|
||||
final Card c = toCard(game);
|
||||
@@ -321,10 +265,10 @@ public class TokenInfo {
|
||||
result.getCurrentState().changeTextIntrinsic(colorMap, typeMap);
|
||||
}
|
||||
|
||||
static public Card getProtoType(final String script, final SpellAbility sa) {
|
||||
return getProtoType(script, sa, true);
|
||||
static public Card getProtoType(final String script, final SpellAbility sa, final Player owner) {
|
||||
return getProtoType(script, sa, owner, true);
|
||||
}
|
||||
static public Card getProtoType(final String script, final SpellAbility sa, boolean applyTextChange) {
|
||||
static public Card getProtoType(final String script, final SpellAbility sa, final Player owner, boolean applyTextChange) {
|
||||
// script might be null, or sa might be null
|
||||
if (script == null || sa == null) {
|
||||
return null;
|
||||
@@ -338,7 +282,7 @@ public class TokenInfo {
|
||||
if (token == null) {
|
||||
return null;
|
||||
}
|
||||
final Card result = Card.fromPaperCard(token, null, game);
|
||||
final Card result = Card.fromPaperCard(token, owner, game);
|
||||
|
||||
if (sa.hasParam("TokenPower")) {
|
||||
String str = sa.getParam("TokenPower");
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.Map;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.TokenCreateTable;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
|
||||
/**
|
||||
@@ -27,9 +28,11 @@ public class ReplaceToken extends ReplacementEffect {
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
/*
|
||||
if (((int) runParams.get(AbilityKey.TokenNum)) <= 0) {
|
||||
return false;
|
||||
}
|
||||
//*/
|
||||
|
||||
if (hasParam("EffectOnly")) {
|
||||
final Boolean effectOnly = (Boolean) runParams.get(AbilityKey.EffectOnly);
|
||||
@@ -41,10 +44,16 @@ public class ReplaceToken extends ReplacementEffect {
|
||||
if (!matchesValidParam("ValidPlayer", runParams.get(AbilityKey.Affected))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*/
|
||||
if (!matchesValidParam("ValidToken", runParams.get(AbilityKey.Token))) {
|
||||
return false;
|
||||
}
|
||||
//*/
|
||||
|
||||
if (filterAmount((TokenCreateTable) runParams.get(AbilityKey.Token)) <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -54,8 +63,13 @@ public class ReplaceToken extends ReplacementEffect {
|
||||
*/
|
||||
@Override
|
||||
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject(AbilityKey.TokenNum, runParams.get(AbilityKey.TokenNum));
|
||||
sa.setReplacingObject(AbilityKey.TokenNum, filterAmount((TokenCreateTable) runParams.get(AbilityKey.Token)));
|
||||
sa.setReplacingObject(AbilityKey.Token, runParams.get(AbilityKey.Token));
|
||||
sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected));
|
||||
}
|
||||
|
||||
|
||||
public int filterAmount(final TokenCreateTable table) {
|
||||
return table.getFilterAmount(getParamOrDefault("ValidPlayer", null), getParamOrDefault("ValidToken", null), this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.util.Set;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import forge.game.CardTraitBase;
|
||||
@@ -274,20 +275,45 @@ public class ReplacementHandler {
|
||||
chosenRE.setOtherChoices(null);
|
||||
return res;
|
||||
}
|
||||
chosenRE.setHasRun(false);
|
||||
hasRun.remove(chosenRE);
|
||||
chosenRE.setOtherChoices(null);
|
||||
|
||||
// Updated Replacements need to be logged elsewhere because its otherwise in the wrong order
|
||||
if (res != ReplacementResult.Updated) {
|
||||
// Log there
|
||||
String message = chosenRE.getDescription();
|
||||
if (!StringUtils.isEmpty(message))
|
||||
if (!StringUtils.isEmpty(message)) {
|
||||
if (chosenRE.getHostCard() != null) {
|
||||
message = TextUtil.fastReplace(message, "CARDNAME", chosenRE.getHostCard().getName());
|
||||
}
|
||||
game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message);
|
||||
}
|
||||
|
||||
// if its updated, try to call event again
|
||||
if (res == ReplacementResult.Updated) {
|
||||
Map<AbilityKey, Object> params = Maps.newHashMap(runParams);
|
||||
|
||||
if (params.containsKey(AbilityKey.EffectOnly)) {
|
||||
params.put(AbilityKey.EffectOnly, true);
|
||||
}
|
||||
ReplacementResult result = run(event, params);
|
||||
switch (result) {
|
||||
case NotReplaced:
|
||||
case Updated: {
|
||||
for (Map.Entry<AbilityKey, Object> e : params.entrySet()) {
|
||||
runParams.put(e.getKey(), e.getValue());
|
||||
}
|
||||
// effect was updated
|
||||
runParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// effect was replaced with something else
|
||||
runParams.put(AbilityKey.ReplacementResult, result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
chosenRE.setHasRun(false);
|
||||
hasRun.remove(chosenRE);
|
||||
chosenRE.setOtherChoices(null);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -300,7 +326,6 @@ public class ReplacementHandler {
|
||||
*/
|
||||
private ReplacementResult executeReplacement(final Map<AbilityKey, Object> runParams,
|
||||
final ReplacementEffect replacementEffect, final Player decider, final Game game) {
|
||||
final Map<String, String> mapParams = replacementEffect.getMapParams();
|
||||
|
||||
SpellAbility effectSA = null;
|
||||
|
||||
@@ -311,10 +336,9 @@ public class ReplacementHandler {
|
||||
host = game.getCardState(host);
|
||||
}
|
||||
|
||||
if (replacementEffect.getOverridingAbility() == null && mapParams.containsKey("ReplaceWith")) {
|
||||
final String effectSVar = mapParams.get("ReplaceWith");
|
||||
if (replacementEffect.getOverridingAbility() == null && replacementEffect.hasParam("ReplaceWith")) {
|
||||
// TODO: the source of replacement effect should be the source of the original effect
|
||||
effectSA = AbilityFactory.getAbility(host, effectSVar, replacementEffect);
|
||||
effectSA = AbilityFactory.getAbility(host, replacementEffect.getParam("ReplaceWith"), replacementEffect);
|
||||
//replacementEffect.setOverridingAbility(effectSA);
|
||||
//effectSA.setTrigger(true);
|
||||
} else if (replacementEffect.getOverridingAbility() != null) {
|
||||
@@ -342,10 +366,10 @@ public class ReplacementHandler {
|
||||
// Decider gets to choose whether or not to apply the replacement.
|
||||
if (replacementEffect.hasParam("Optional")) {
|
||||
Player optDecider = decider;
|
||||
if (mapParams.containsKey("OptionalDecider") && (effectSA != null)) {
|
||||
if (replacementEffect.hasParam("OptionalDecider") && (effectSA != null)) {
|
||||
effectSA.setActivatingPlayer(host.getController());
|
||||
optDecider = AbilityUtils.getDefinedPlayers(host,
|
||||
mapParams.get("OptionalDecider"), effectSA).get(0);
|
||||
replacementEffect.getParam("OptionalDecider"), effectSA).get(0);
|
||||
}
|
||||
|
||||
Card cardForUi = host.getCardForUi();
|
||||
@@ -360,12 +384,12 @@ public class ReplacementHandler {
|
||||
}
|
||||
}
|
||||
|
||||
boolean isPrevent = mapParams.containsKey("Prevent") && mapParams.get("Prevent").equals("True");
|
||||
if (isPrevent || mapParams.containsKey("PreventionEffect")) {
|
||||
boolean isPrevent = "True".equals(replacementEffect.getParam("Prevent"));
|
||||
if (isPrevent || replacementEffect.hasParam("PreventionEffect")) {
|
||||
if (Boolean.TRUE.equals(runParams.get(AbilityKey.NoPreventDamage))) {
|
||||
// If can't prevent damage, result is not replaced
|
||||
// But still put "prevented" amount for buffered SA
|
||||
if (mapParams.containsKey("AlwaysReplace")) {
|
||||
if (replacementEffect.hasParam("AlwaysReplace")) {
|
||||
runParams.put(AbilityKey.PreventedAmount, runParams.get(AbilityKey.DamageAmount));
|
||||
} else {
|
||||
runParams.put(AbilityKey.PreventedAmount, 0);
|
||||
@@ -377,11 +401,9 @@ public class ReplacementHandler {
|
||||
}
|
||||
}
|
||||
|
||||
if (mapParams.containsKey("Skip")) {
|
||||
if (mapParams.get("Skip").equals("True")) {
|
||||
if ("True".equals(replacementEffect.getParam("Skip"))) {
|
||||
return ReplacementResult.Skipped; // Event is skipped.
|
||||
}
|
||||
}
|
||||
|
||||
Player player = host.getController();
|
||||
|
||||
@@ -394,6 +416,11 @@ public class ReplacementHandler {
|
||||
// The SA if buffered, but replacement result should be set to Replaced
|
||||
runParams.put(AbilityKey.ReplacementResult, ReplacementResult.Replaced);
|
||||
}
|
||||
|
||||
// these ones are special for updating
|
||||
if (apiType == ApiType.ReplaceToken || apiType == ApiType.ReplaceEffect || apiType == ApiType.ReplaceMana) {
|
||||
runParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
|
||||
}
|
||||
}
|
||||
|
||||
// if the spellability is a replace effect then its some new logic
|
||||
|
||||
@@ -2,11 +2,8 @@ Name:Academy Manufactor
|
||||
ManaCost:3
|
||||
Types:Artifact Creature Assembly-Worker
|
||||
PT:1/3
|
||||
R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ValidToken$ Clue,Food,Treasure | ReplaceWith$ DBToken | Description$ If you would create a Clue, Food, or Treasure token, instead create one of each.
|
||||
SVar:DBToken:DB$ Token | TokenScript$ c_a_clue_draw | TokenAmount$ X | SubAbility$ DBToken2
|
||||
SVar:DBToken2:DB$ Token | TokenScript$ c_a_food_sac | TokenAmount$ X | SubAbility$ DBToken3
|
||||
SVar:DBToken3:DB$ Token | TokenScript$ c_a_treasure_sac | TokenAmount$ X
|
||||
SVar:X:ReplaceCount$TokenNum
|
||||
R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ValidToken$ Clue,Food,Treasure | ReplaceWith$ TokenReplace | Description$ If you would create a Clue, Food, or Treasure token, instead create one of each.
|
||||
SVar:TokenReplace:DB$ ReplaceToken | Type$ ReplaceToken | ValidCard$ Clue,Food,Treasure | TokenScript$ c_a_clue_draw,c_a_food_sac,c_a_treasure_sac
|
||||
DeckHas:Ability$Sacrifice & Ability$Token & Ability$LifeGain
|
||||
DeckHints:Ability$Investigate
|
||||
Oracle:If you would create a Clue, Food, or Treasure token, instead create one of each.
|
||||
|
||||
@@ -3,8 +3,7 @@ ManaCost:2 G U
|
||||
Types:Legendary Creature Merfolk Wizard
|
||||
PT:2/2
|
||||
K:Ward:2
|
||||
R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ DoubleToken | Description$ If one or more tokens would be created under your control, twice that many of those tokens are created instead.
|
||||
SVar:DoubleToken:DB$ ReplaceEffect | VarName$ TokenNum | VarValue$ X
|
||||
SVar:X:ReplaceCount$TokenNum/Twice
|
||||
R:Event$ CreateToken | ActiveZones$ Battlefield | ValidToken$ Card.YouCtrl | ReplaceWith$ DoubleToken | Description$ If one or more tokens would be created under your control, twice that many of those tokens are created instead.
|
||||
SVar:DoubleToken:DB$ ReplaceToken | Type$ Amount | ValidCard$ Card.YouCtrl
|
||||
DeckHints:Ability$Token
|
||||
Oracle:Ward {2} (Whenever this creature becomes the target of a spell or ability an opponent controls, counter it unless that player pays {2}.)\nIf one or more tokens would be created under your control, twice that many of those tokens are created instead.
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
Name:Anointed Procession
|
||||
ManaCost:3 W
|
||||
Types:Enchantment
|
||||
R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ DoubleToken | EffectOnly$ True | Description$ If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead.
|
||||
SVar:DoubleToken:DB$ ReplaceEffect | VarName$ TokenNum | VarValue$ X
|
||||
SVar:X:ReplaceCount$TokenNum/Twice
|
||||
R:Event$ CreateToken | ActiveZones$ Battlefield | ValidToken$ Card.YouCtrl | ReplaceWith$ DoubleToken | EffectOnly$ True | Description$ If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead.
|
||||
SVar:DoubleToken:DB$ ReplaceToken | Type$ Amount | ValidCard$ Card.YouCtrl
|
||||
DeckNeeds:Ability$Token
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/anointed_procession.jpg
|
||||
Oracle:If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead.
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
Name:Bestial Menace
|
||||
ManaCost:3 G G
|
||||
Types:Sorcery
|
||||
A:SP$ Token | Cost$ 3 G G | TokenAmount$ 1 | TokenScript$ g_1_1_snake | TokenOwner$ You | LegacyImage$ | SubAbility$ DBWolfToken | ChangeZoneTable$ True | SpellDescription$ Create a 1/1 green Snake creature token,
|
||||
SVar:DBWolfToken:DB$ Token | TokenAmount$ 1 | TokenScript$ g_2_2_wolf | TokenOwner$ You | LegacyImage$ g 2 2 wolf wwk | SubAbility$ DBElephantToken | SpellDescription$ a 2/2 green Wolf creature token,
|
||||
SVar:DBElephantToken:DB$ Token | TokenAmount$ 1 | TokenScript$ g_3_3_elephant | TokenOwner$ You | LegacyImage$ g 3 3 elephant wwk | SubAbility$ DBResolve | SpellDescription$ and a 3/3 green Elephant creature token.
|
||||
SVar:DBResolve:DB$ ChangeZoneResolve
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/bestial_menace.jpg
|
||||
A:SP$ Token | Cost$ 3 G G | TokenAmount$ 1 | TokenScript$ g_1_1_snake,g_2_2_wolf,g_3_3_elephant | TokenOwner$ You | SpellDescription$ Create a 1/1 green Snake creature token, a 2/2 green Wolf creature token, and a 3/3 green Elephant creature token.
|
||||
Oracle:Create a 1/1 green Snake creature token, a 2/2 green Wolf creature token, and a 3/3 green Elephant creature token.
|
||||
|
||||
@@ -3,12 +3,10 @@ ManaCost:2 G
|
||||
Types:Legendary Creature Squirrel Warrior
|
||||
PT:3/3
|
||||
K:Forestwalk
|
||||
R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ DBReplace | Description$ If one or more tokens would be created under your control, those tokens plus that many 1/1 green Squirrel creature tokens are created instead.
|
||||
SVar:DBReplace:DB$ ReplaceEffect | VarName$ TokenNum | VarValue$ Y | SubAbility$ DBToken
|
||||
SVar:DBToken:DB$ Token | TokenAmount$ Y | TokenScript$ g_1_1_squirrel
|
||||
R:Event$ CreateToken | ActiveZones$ Battlefield | ValidToken$ Card.YouCtrl | ReplaceWith$ DBReplace | Description$ If one or more tokens would be created under your control, those tokens plus that many 1/1 green Squirrel creature tokens are created instead.
|
||||
SVar:DBReplace:DB$ ReplaceToken | Type$ AddToken | ValidCard$ Card.YouCtrl | TokenScript$ g_1_1_squirrel
|
||||
A:AB$ Pump | Cost$ B Sac<X/Squirrel> | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ +X | NumDef$ -X | SpellDescription$ Target creature gets +X/-X until end of turn.
|
||||
SVar:X:Count$xPaid
|
||||
SVar:Y:ReplaceCount$TokenNum
|
||||
DeckHas:Ability$Token
|
||||
DeckHints:Type$Squirrel
|
||||
Oracle:Forestwalk (This creature can't be blocked as long as defending player controls a Forest.)\nIf one or more tokens would be created under your control, those tokens plus that many 1/1 green Squirrel creature tokens are created instead.\n{B}, Sacrifice X Squirrels: Target creature gets +X/-X until end of turn.
|
||||
|
||||
@@ -5,7 +5,6 @@ PT:2/2
|
||||
K:Flash
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigEffect | TriggerDescription$ When CARDNAME enters the battlefield, each token that would be created under an opponent's control this turn is created under your control instead.
|
||||
SVar:TrigEffect:DB$ Effect | Name$ Crafty Cutpurse Effect | ReplacementEffects$ OppCreatEnters | SpellDescription$ Each token that would be created under an opponent's control this turn is created under your control instead.
|
||||
SVar:OppCreatEnters:Event$ CreateToken | ActiveZones$ Command | ValidPlayer$ Player.Opponent | ReplaceWith$ ETBYourCtrl | Layer$ Control | Description$ Each token that would be created under an opponent's control this turn is created under your control instead.
|
||||
SVar:ETBYourCtrl:DB$ ReplaceEffect | VarName$ Affected | VarValue$ You | VarType$ Player
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/crafty_cutpurse.jpg
|
||||
SVar:OppCreatEnters:Event$ CreateToken | ActiveZones$ Command | ValidToken$ Card.OppCtrl | ReplaceWith$ ETBYourCtrl | Layer$ Control | Description$ Each token that would be created under an opponent's control this turn is created under your control instead.
|
||||
SVar:ETBYourCtrl:DB$ ReplaceToken | Type$ ReplaceController | ValidCard$ Card.OppCtrl | NewController$ You
|
||||
Oracle:Flash\nWhen Crafty Cutpurse enters the battlefield, each token that would be created under an opponent's control this turn is created under your control instead.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Name:Divine Visitation
|
||||
ManaCost:3 W W
|
||||
Types:Enchantment
|
||||
R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ TokenReplace | ValidToken$ Creature | Description$ If one or more creature tokens would be created under your control, that many 4/4 white Angel creature tokens with flying and vigilance are created instead.
|
||||
SVar:TokenReplace:DB$ ReplaceEffect | VarName$ Token | VarValue$ w_4_4_angel_flying_vigilance | VarType$ TokenScript
|
||||
R:Event$ CreateToken | ActiveZones$ Battlefield | ValidToken$ Creature.YouCtrl | ReplaceWith$ TokenReplace | Description$ If one or more creature tokens would be created under your control, that many 4/4 white Angel creature tokens with flying and vigilance are created instead.
|
||||
SVar:TokenReplace:DB$ ReplaceToken | Type$ ReplaceToken | ValidCard$ Creature.YouCtrl | TokenScript$ w_4_4_angel_flying_vigilance
|
||||
DeckNeeds:Ability$Token
|
||||
Oracle:If one or more creature tokens would be created under your control, that many 4/4 white Angel creature tokens with flying and vigilance are created instead.
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
Name:Doubling Season
|
||||
ManaCost:4 G
|
||||
Types:Enchantment
|
||||
R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ DoubleToken | EffectOnly$ True | Description$ If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead.
|
||||
SVar:DoubleToken:DB$ ReplaceEffect | VarName$ TokenNum | VarValue$ X
|
||||
R:Event$ CreateToken | ActiveZones$ Battlefield | ValidToken$ Card.YouCtrl | ReplaceWith$ DoubleToken | EffectOnly$ True | Description$ If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead.
|
||||
SVar:DoubleToken:DB$ ReplaceToken | Type$ Amount | ValidCard$ Card.YouCtrl
|
||||
R:Event$ AddCounter | ActiveZones$ Battlefield | ValidCard$ Permanent.YouCtrl | EffectOnly$ True | ReplaceWith$ DoubleCounters | Description$ If an effect would put one or more counters on a permanent you control, it puts twice that many of those counters on that permanent instead.
|
||||
SVar:DoubleCounters:DB$ ReplaceEffect | VarName$ CounterNum | VarValue$ Y
|
||||
SVar:X:ReplaceCount$TokenNum/Twice
|
||||
SVar:Y:ReplaceCount$CounterNum/Twice
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/doubling_season.jpg
|
||||
Oracle:If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead.\nIf an effect would put one or more counters on a permanent you control, it puts twice that many of those counters on that permanent instead.
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
Name:Forbidden Friendship
|
||||
ManaCost:1 R
|
||||
Types:Sorcery
|
||||
A:SP$ Token | Cost$ 1 R | TokenAmount$ 1 | TokenScript$ r_1_1_dinosaur_haste | TokenOwner$ You | LegacyImage$ r 1 1 dinosaur haste iko | ChangeZoneTable$ True | SubAbility$ DBToken | SpellDescription$ Create a 1/1 red Dinosaur creature token with haste and a 1/1 white Human Soldier creature token.
|
||||
SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_1_1_human_soldier | TokenOwner$ You | LegacyImage$ w 1 1 human soldier iko | SubAbility$ DBResolve
|
||||
SVar:DBResolve:DB$ ChangeZoneResolve
|
||||
A:SP$ Token | Cost$ 1 R | TokenAmount$ 1 | TokenScript$ r_1_1_dinosaur_haste,w_1_1_human_soldier | TokenOwner$ You | SpellDescription$ Create a 1/1 red Dinosaur creature token with haste and a 1/1 white Human Soldier creature token.
|
||||
DeckHas:Ability$Token
|
||||
Oracle:Create a 1/1 red Dinosaur creature token with haste and a 1/1 white Human Soldier creature token.
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
Name:Mascot Exhibition
|
||||
ManaCost:7
|
||||
Types:Sorcery Lesson
|
||||
A:SP$ Token | Cost$ 7 | TokenAmount$ 1 | TokenScript$ wb_2_1_inkling_flying | TokenOwner$ You | SubAbility$ DBSpiritToken | ChangeZoneTable$ True | SpellDescription$ Create a 2/1 white and black Inkling creature token with flying,
|
||||
SVar:DBSpiritToken:DB$ Token | TokenAmount$ 1 | TokenScript$ rw_3_2_spirit | TokenOwner$ You | SubAbility$ DBElemToken | SpellDescription$ a 3/2 red and white Spirit creature token,
|
||||
SVar:DBElemToken:DB$ Token | TokenAmount$ 1 | TokenScript$ ur_4_4_elemental | TokenOwner$ You | SubAbility$ DBResolve | SpellDescription$ and a 4/4 blue and red Elemental creature token.
|
||||
SVar:DBResolve:DB$ ChangeZoneResolve
|
||||
A:SP$ Token | Cost$ 7 | TokenAmount$ 1 | TokenScript$ wb_2_1_inkling_flying,rw_3_2_spirit,ur_4_4_elemental | TokenOwner$ You | SpellDescription$ Create a 2/1 white and black Inkling creature token with flying, a 3/2 red and white Spirit creature token, and a 4/4 blue and red Elemental creature token.
|
||||
DeckHas:Ability$Token
|
||||
Oracle:Create a 2/1 white and black Inkling creature token with flying, a 3/2 red and white Spirit creature token, and a 4/4 blue and red Elemental creature token.
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
Name:Parallel Lives
|
||||
ManaCost:3 G
|
||||
Types:Enchantment
|
||||
R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ DoubleToken | EffectOnly$ True | Description$ If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead.
|
||||
SVar:DoubleToken:DB$ ReplaceEffect | VarName$ TokenNum | VarValue$ X
|
||||
SVar:X:ReplaceCount$TokenNum/Twice
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/parallel_lives.jpg
|
||||
R:Event$ CreateToken | ActiveZones$ Battlefield | ValidToken$ Card.YouCtrl | ReplaceWith$ DoubleToken | EffectOnly$ True | Description$ If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead.
|
||||
SVar:DoubleToken:DB$ ReplaceToken | Type$ Amount | ValidCard$ Card.YouCtrl
|
||||
Oracle:If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead.
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
Name:Primal Vigor
|
||||
ManaCost:4 G
|
||||
Types:Enchantment
|
||||
R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ Player | ReplaceWith$ DoubleToken | Description$ If one or more tokens would be created, twice that many of those tokens are created instead.
|
||||
SVar:DoubleToken:DB$ ReplaceEffect | VarName$ TokenNum | VarValue$ X
|
||||
R:Event$ CreateToken | ActiveZones$ Battlefield | ReplaceWith$ DoubleToken | Description$ If one or more tokens would be created, twice that many of those tokens are created instead.
|
||||
SVar:DoubleToken:DB$ ReplaceToken | Type$ Amount
|
||||
R:Event$ AddCounter | ActiveZones$ Battlefield | ValidCard$ Creature | ValidCounterType$ P1P1 | ReplaceWith$ DoubleP1P1Counters | Description$ If one or more +1/+1 counters would be put on a creature, twice that many +1/+1 counters are put on that creature instead.
|
||||
SVar:DoubleP1P1Counters:DB$ ReplaceEffect | VarName$ CounterNum | VarValue$ Y
|
||||
SVar:X:ReplaceCount$TokenNum/Twice
|
||||
SVar:Y:ReplaceCount$CounterNum/Twice
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/primal_vigor.jpg
|
||||
Oracle:If one or more tokens would be created, twice that many of those tokens are created instead.\nIf one or more +1/+1 counters would be put on a creature, twice that many +1/+1 counters are put on that creature instead.
|
||||
|
||||
@@ -2,10 +2,9 @@ Name:Selesnya Loft Gardens
|
||||
ManaCost:no cost
|
||||
Types:Plane Ravnica
|
||||
R:Event$ CreateToken | ActiveZones$ Command | ReplaceWith$ DoubleToken | EffectOnly$ True | Description$ If an effect would create one or more tokens, it creates twice that many of those tokens instead.
|
||||
SVar:DoubleToken:DB$ ReplaceEffect | VarName$ TokenNum | VarValue$ Y
|
||||
SVar:DoubleToken:DB$ ReplaceToken | Type$ Amount
|
||||
R:Event$ AddCounter | ActiveZones$ Command | ValidCard$ Permanent | EffectOnly$ True | ReplaceWith$ DoubleCounters | Description$ If an effect would put one or more counters on a permanent, it puts twice that many of those counters on that permanent instead.
|
||||
SVar:DoubleCounters:DB$ ReplaceEffect | VarName$ CounterNum | VarValue$ Z
|
||||
SVar:Y:ReplaceCount$TokenNum/Twice
|
||||
SVar:Z:ReplaceCount$CounterNum/Twice
|
||||
T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll {CHAOS}, until end of turn, whenever you tap a land for mana, add one mana of any type that land produced.
|
||||
SVar:RolledChaos:DB$ Effect | AILogic$ Always | Triggers$ TrigTapForMana
|
||||
|
||||
@@ -3,9 +3,7 @@ ManaCost:4 U
|
||||
Types:Creature Vedalken Wizard
|
||||
PT:2/1
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield, create a 1/1 green Squirrel creature token and a 0/3 blue Crab creature token.
|
||||
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ g_1_1_squirrel | TokenOwner$ You | ChangeZoneTable$ True | SubAbility$ DBCrabToken
|
||||
SVar:DBCrabToken:DB$ Token | TokenAmount$ 1 | TokenScript$ u_0_3_crab | TokenOwner$ You | SubAbility$ DBResolve
|
||||
SVar:DBResolve:DB$ ChangeZoneResolve
|
||||
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ g_1_1_squirrel,u_0_3_crab | TokenOwner$ You
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigCopy | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, create a token that's a copy of target token you control.
|
||||
SVar:TrigCopy:DB$ CopyPermanent | ValidTgts$ Permanent.token+YouCtrl | TgtPrompt$ Select target token you control
|
||||
DeckHas:Ability$Token
|
||||
|
||||
@@ -5,10 +5,7 @@ PT:9/9
|
||||
K:Flying
|
||||
K:Vigilance
|
||||
K:Trample
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigTokenFly | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, create a 3/3 colorless Golem artifact creature token with flying, a 3/3 colorless Golem artifact creature token with vigilance, and a 3/3 colorless Golem artifact creature token with trample.
|
||||
SVar:TrigTokenFly:DB$Token | TokenAmount$ 1 | TokenScript$ c_3_3_a_golem_flying | ChangeZoneTable$ True | SubAbility$ DBTokenVig
|
||||
SVar:DBTokenVig:DB$Token | TokenAmount$ 1 | TokenScript$ c_3_3_a_golem_vigilance | SubAbility$ DBTokenTra
|
||||
SVar:DBTokenTra:DB$Token | TokenAmount$ 1 | TokenScript$ c_3_3_a_golem_trample | SubAbility$ DBResolve
|
||||
SVar:DBResolve:DB$ ChangeZoneResolve
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME dies, create a 3/3 colorless Golem artifact creature token with flying, a 3/3 colorless Golem artifact creature token with vigilance, and a 3/3 colorless Golem artifact creature token with trample.
|
||||
SVar:TrigToken:DB$Token | TokenAmount$ 1 | TokenScript$ c_3_3_a_golem_flying,c_3_3_a_golem_vigilance,c_3_3_a_golem_trample
|
||||
DeckHas:Ability$Token
|
||||
Oracle:Flying, vigilance, trample\nWhen Triplicate Titan dies, create a 3/3 colorless Golem artifact creature token with flying, a 3/3 colorless Golem artifact creature token with vigilance, and a 3/3 colorless Golem artifact creature token with trample.
|
||||
|
||||
@@ -2,9 +2,8 @@ Name:Xorn
|
||||
ManaCost:2 R
|
||||
Types:Creature Elemental
|
||||
PT:3/2
|
||||
R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ValidToken$ Treasure | ReplaceWith$ AdditionalToken | Description$ If you would create one or more Treasure tokens, instead create those tokens plus an additional Treasure token.
|
||||
SVar:AdditionalToken:DB$ ReplaceEffect | VarName$ TokenNum | VarValue$ X
|
||||
SVar:X:ReplaceCount$TokenNum/Plus.1
|
||||
R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ValidToken$ Treasure | ReplaceWith$ DBReplace | Description$ If you would create one or more Treasure tokens, instead create those tokens plus an additional Treasure token.
|
||||
SVar:DBReplace:DB$ ReplaceToken | Type$ AddToken | Amount$ 1 | TokenScript$ c_a_treasure_sac
|
||||
DeckNeeds:Type$Token
|
||||
AI:RemoveDeck:Random
|
||||
Oracle:If you would create one or more Treasure tokens, instead create those tokens plus an additional Treasure token.
|
||||
|
||||
@@ -1324,7 +1324,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
}
|
||||
if (sa.hasParam("TokenScript")) {
|
||||
sa.setActivatingPlayer(player);
|
||||
Card protoType = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa);
|
||||
Card protoType = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa, null);
|
||||
for (String type : protoType.getType().getCreatureTypes()) {
|
||||
Integer count = typesInDeck.get(type);
|
||||
if (count == null) {
|
||||
@@ -1340,7 +1340,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
if (sa != null) {
|
||||
if (sa.hasParam("TokenScript")) {
|
||||
sa.setActivatingPlayer(player);
|
||||
Card protoType = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa);
|
||||
Card protoType = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa, null);
|
||||
for (String type : protoType.getType().getCreatureTypes()) {
|
||||
Integer count = typesInDeck.get(type);
|
||||
if (count == null) {
|
||||
|
||||
Reference in New Issue
Block a user