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.ReplaceEffect, AlwaysPlayAi.class)
|
||||||
.put(ApiType.ReplaceDamage, AlwaysPlayAi.class)
|
.put(ApiType.ReplaceDamage, AlwaysPlayAi.class)
|
||||||
.put(ApiType.ReplaceSplitDamage, AlwaysPlayAi.class)
|
.put(ApiType.ReplaceSplitDamage, AlwaysPlayAi.class)
|
||||||
|
.put(ApiType.ReplaceToken, AlwaysPlayAi.class)
|
||||||
.put(ApiType.RestartGame, RestartGameAi.class)
|
.put(ApiType.RestartGame, RestartGameAi.class)
|
||||||
.put(ApiType.Reveal, RevealAi.class)
|
.put(ApiType.Reveal, RevealAi.class)
|
||||||
.put(ApiType.RevealHand, RevealHandAi.class)
|
.put(ApiType.RevealHand, RevealHandAi.class)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public class AmassAi extends SpellAbilityAi {
|
|||||||
final String tokenScript = "b_0_0_zombie_army";
|
final String tokenScript = "b_0_0_zombie_army";
|
||||||
final int amount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Num", "1"), sa);
|
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) {
|
if (token == null) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -358,7 +358,7 @@ public class TokenAi extends SpellAbilityAi {
|
|||||||
if (!sa.hasParam("TokenScript")) {
|
if (!sa.hasParam("TokenScript")) {
|
||||||
throw new RuntimeException("Spell Ability has no TokenScript: " + sa);
|
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) {
|
if (result == null) {
|
||||||
throw new RuntimeException("don't find Token for TokenScript: " + sa.getParam("TokenScript"));
|
throw new RuntimeException("don't find Token for TokenScript: " + sa.getParam("TokenScript"));
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ public enum ApiType {
|
|||||||
ReplaceEffect (ReplaceEffect.class),
|
ReplaceEffect (ReplaceEffect.class),
|
||||||
ReplaceMana (ReplaceManaEffect.class),
|
ReplaceMana (ReplaceManaEffect.class),
|
||||||
ReplaceDamage (ReplaceDamageEffect.class),
|
ReplaceDamage (ReplaceDamageEffect.class),
|
||||||
|
ReplaceToken (ReplaceTokenEffect.class),
|
||||||
ReplaceSplitDamage (ReplaceSplitDamageEffect.class),
|
ReplaceSplitDamage (ReplaceSplitDamageEffect.class),
|
||||||
RestartGame (RestartGameEffect.class),
|
RestartGame (RestartGameEffect.class),
|
||||||
Reveal (RevealEffect.class),
|
Reveal (RevealEffect.class),
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import forge.game.card.CardPredicates;
|
|||||||
import forge.game.card.CardZoneTable;
|
import forge.game.card.CardZoneTable;
|
||||||
import forge.game.card.CounterEnumType;
|
import forge.game.card.CounterEnumType;
|
||||||
import forge.game.card.CounterType;
|
import forge.game.card.CounterType;
|
||||||
import forge.game.card.token.TokenInfo;
|
|
||||||
import forge.game.event.GameEventCombatChanged;
|
import forge.game.event.GameEventCombatChanged;
|
||||||
import forge.game.event.GameEventTokenCreated;
|
import forge.game.event.GameEventTokenCreated;
|
||||||
import forge.game.player.Player;
|
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 int amount = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("Num", "1"), sa);
|
||||||
final boolean remember = sa.hasParam("RememberAmass");
|
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
|
// create army token if needed
|
||||||
if (CardLists.count(activator.getCardsIn(ZoneType.Battlefield), CardPredicates.isType("Army")) == 0) {
|
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);
|
triggerList.triggerChangesZoneAll(game, sa);
|
||||||
|
triggerList.clear();
|
||||||
|
|
||||||
if (!useZoneTable) {
|
|
||||||
triggerList.triggerChangesZoneAll(game, sa);
|
|
||||||
triggerList.clear();
|
|
||||||
}
|
|
||||||
game.fireEvent(new GameEventTokenCreated());
|
game.fireEvent(new GameEventTokenCreated());
|
||||||
|
|
||||||
|
if (combatChanged.isTrue()) {
|
||||||
|
game.updateCombatForView();
|
||||||
|
game.fireEvent(new GameEventCombatChanged());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (combatChanged.isTrue()) {
|
|
||||||
game.updateCombatForView();
|
|
||||||
game.fireEvent(new GameEventCombatChanged());
|
|
||||||
}
|
|
||||||
Map<String, Object> params = Maps.newHashMap();
|
Map<String, Object> params = Maps.newHashMap();
|
||||||
params.put("CounterType", CounterType.get(CounterEnumType.P1P1));
|
params.put("CounterType", CounterType.get(CounterEnumType.P1P1));
|
||||||
params.put("Amount", 1);
|
params.put("Amount", 1);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import forge.game.card.CardFactory;
|
|||||||
import forge.game.card.CardLists;
|
import forge.game.card.CardLists;
|
||||||
import forge.game.card.CardPredicates;
|
import forge.game.card.CardPredicates;
|
||||||
import forge.game.card.CardZoneTable;
|
import forge.game.card.CardZoneTable;
|
||||||
|
import forge.game.card.TokenCreateTable;
|
||||||
import forge.game.event.GameEventCombatChanged;
|
import forge.game.event.GameEventCombatChanged;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.player.PlayerActionConfirmMode;
|
import forge.game.player.PlayerActionConfirmMode;
|
||||||
@@ -177,15 +178,18 @@ public class CopyPermanentEffect extends TokenEffectBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MutableBoolean combatChanged = new MutableBoolean(false);
|
MutableBoolean combatChanged = new MutableBoolean(false);
|
||||||
|
TokenCreateTable tokenTable = new TokenCreateTable();
|
||||||
|
|
||||||
for (final Card c : tgtCards) {
|
for (final Card c : tgtCards) {
|
||||||
// if it only targets player, it already got all needed cards from defined
|
// if it only targets player, it already got all needed cards from defined
|
||||||
if (sa.usesTargeting() && !sa.getTargetRestrictions().canTgtPlayer() && !c.canBeTargetedBy(sa)) {
|
if (sa.usesTargeting() && !sa.getTargetRestrictions().canTgtPlayer() && !c.canBeTargetedBy(sa)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
tokenTable.put(controller, getProtoType(sa, c, controller), numCopies);
|
||||||
makeTokens(getProtoType(sa, c), controller, sa, numCopies, true, true, triggerList, combatChanged);
|
|
||||||
} // end foreach Card
|
} // end foreach Card
|
||||||
|
|
||||||
|
makeTokenTable(tokenTable, true, triggerList, combatChanged, sa);
|
||||||
|
|
||||||
if (!useZoneTable) {
|
if (!useZoneTable) {
|
||||||
triggerList.triggerChangesZoneAll(game, sa);
|
triggerList.triggerChangesZoneAll(game, sa);
|
||||||
triggerList.clear();
|
triggerList.clear();
|
||||||
@@ -196,9 +200,8 @@ public class CopyPermanentEffect extends TokenEffectBase {
|
|||||||
}
|
}
|
||||||
} // end resolve
|
} // 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 Card host = sa.getHostCard();
|
||||||
final Player newOwner = sa.getActivatingPlayer();
|
|
||||||
int id = newOwner == null ? 0 : newOwner.getGame().nextCardId();
|
int id = newOwner == null ? 0 : newOwner.getGame().nextCardId();
|
||||||
final Card copy = new Card(id, original.getPaperCard(), host.getGame());
|
final Card copy = new Card(id, original.getPaperCard(), host.getGame());
|
||||||
copy.setOwner(newOwner);
|
copy.setOwner(newOwner);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import forge.game.Game;
|
|||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardZoneTable;
|
import forge.game.card.CardZoneTable;
|
||||||
import forge.game.card.token.TokenInfo;
|
|
||||||
import forge.game.event.GameEventCombatChanged;
|
import forge.game.event.GameEventCombatChanged;
|
||||||
import forge.game.event.GameEventTokenCreated;
|
import forge.game.event.GameEventTokenCreated;
|
||||||
import forge.game.player.Player;
|
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 int amount = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("Num", "1"), sa);
|
||||||
|
|
||||||
final String tokenScript = "c_a_clue_draw";
|
// Investigate in Sequence
|
||||||
final Card prototype = TokenInfo.getProtoType(tokenScript, sa, false);
|
|
||||||
|
|
||||||
for (final Player p : getTargetPlayers(sa)) {
|
for (final Player p : getTargetPlayers(sa)) {
|
||||||
for (int i = 0; i < amount; i++) {
|
for (int i = 0; i < amount; i++) {
|
||||||
CardZoneTable triggerList = new CardZoneTable();
|
CardZoneTable triggerList = new CardZoneTable();
|
||||||
MutableBoolean combatChanged = new MutableBoolean(false);
|
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);
|
triggerList.triggerChangesZoneAll(game, sa);
|
||||||
p.addInvestigatedThisTurn();
|
p.addInvestigatedThisTurn();
|
||||||
|
|||||||
@@ -3,12 +3,6 @@ package forge.game.ability.effects;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.GameObject;
|
||||||
import forge.game.ability.AbilityKey;
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
@@ -17,25 +11,21 @@ import forge.game.card.Card;
|
|||||||
import forge.game.card.token.TokenInfo;
|
import forge.game.card.token.TokenInfo;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.replacement.ReplacementResult;
|
import forge.game.replacement.ReplacementResult;
|
||||||
import forge.game.replacement.ReplacementType;
|
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.util.TextUtil;
|
|
||||||
|
|
||||||
public class ReplaceEffect extends SpellAbilityEffect {
|
public class ReplaceEffect extends SpellAbilityEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resolve(SpellAbility sa) {
|
public void resolve(SpellAbility sa) {
|
||||||
final Card card = sa.getHostCard();
|
final Card card = sa.getHostCard();
|
||||||
final Game game = card.getGame();
|
|
||||||
|
|
||||||
final AbilityKey varName = AbilityKey.fromString(sa.getParam("VarName"));
|
final AbilityKey varName = AbilityKey.fromString(sa.getParam("VarName"));
|
||||||
final String varValue = sa.getParam("VarValue");
|
final String varValue = sa.getParam("VarValue");
|
||||||
final String type = sa.getParamOrDefault("VarType", "amount");
|
final String type = sa.getParamOrDefault("VarType", "amount");
|
||||||
final ReplacementType retype = sa.getReplacementEffect().getMode();
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<AbilityKey, Object> originalParams = (Map<AbilityKey, Object>) sa.getReplacingObject(AbilityKey.OriginalParams);
|
Map<AbilityKey, Object> params = (Map<AbilityKey, Object>) sa.getReplacingObject(AbilityKey.OriginalParams);
|
||||||
Map<AbilityKey, Object> params = Maps.newHashMap(originalParams);
|
|
||||||
|
|
||||||
if ("Card".equals(type)) {
|
if ("Card".equals(type)) {
|
||||||
List<Card> list = AbilityUtils.getDefinedCards(card, varValue, sa);
|
List<Card> list = AbilityUtils.getDefinedCards(card, varValue, sa);
|
||||||
@@ -53,7 +43,7 @@ public class ReplaceEffect extends SpellAbilityEffect {
|
|||||||
params.put(varName, list.get(0));
|
params.put(varName, list.get(0));
|
||||||
}
|
}
|
||||||
} else if ("TokenScript".equals(type)) {
|
} else if ("TokenScript".equals(type)) {
|
||||||
final Card protoType = TokenInfo.getProtoType(varValue, sa);
|
final Card protoType = TokenInfo.getProtoType(varValue, sa, sa.getActivatingPlayer());
|
||||||
if (protoType != null) {
|
if (protoType != null) {
|
||||||
params.put(varName, protoType);
|
params.put(varName, protoType);
|
||||||
}
|
}
|
||||||
@@ -61,42 +51,7 @@ public class ReplaceEffect extends SpellAbilityEffect {
|
|||||||
params.put(varName, AbilityUtils.calculateAmount(card, varValue, sa));
|
params.put(varName, AbilityUtils.calculateAmount(card, varValue, sa));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.containsKey(AbilityKey.EffectOnly)) {
|
params.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,20 +4,15 @@ import java.util.Map;
|
|||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
|
|
||||||
import forge.card.ColorSet;
|
import forge.card.ColorSet;
|
||||||
import forge.card.MagicColor;
|
import forge.card.MagicColor;
|
||||||
import forge.game.Game;
|
|
||||||
import forge.game.GameLogEntryType;
|
|
||||||
import forge.game.ability.AbilityKey;
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.replacement.ReplacementResult;
|
import forge.game.replacement.ReplacementResult;
|
||||||
import forge.game.replacement.ReplacementType;
|
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.util.TextUtil;
|
|
||||||
|
|
||||||
public class ReplaceManaEffect extends SpellAbilityEffect {
|
public class ReplaceManaEffect extends SpellAbilityEffect {
|
||||||
|
|
||||||
@@ -25,17 +20,14 @@ public class ReplaceManaEffect extends SpellAbilityEffect {
|
|||||||
public void resolve(SpellAbility sa) {
|
public void resolve(SpellAbility sa) {
|
||||||
final Card card = sa.getHostCard();
|
final Card card = sa.getHostCard();
|
||||||
final Player player = sa.getActivatingPlayer();
|
final Player player = sa.getActivatingPlayer();
|
||||||
final Game game = card.getGame();
|
|
||||||
|
|
||||||
// outside of Replacement Effect, unwanted result
|
// outside of Replacement Effect, unwanted result
|
||||||
if (!sa.isReplacementAbility()) {
|
if (!sa.isReplacementAbility()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ReplacementType event = sa.getReplacementEffect().getMode();
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<AbilityKey, Object> originalParams = (Map<AbilityKey, Object>) sa.getReplacingObject(AbilityKey.OriginalParams);
|
Map<AbilityKey, Object> params = (Map<AbilityKey, Object>) sa.getReplacingObject(AbilityKey.OriginalParams);
|
||||||
Map<AbilityKey, Object> params = Maps.newHashMap(originalParams);
|
|
||||||
|
|
||||||
String replaced = (String)sa.getReplacingObject(AbilityKey.Mana);
|
String replaced = (String)sa.getReplacingObject(AbilityKey.Mana);
|
||||||
if (sa.hasParam("ReplaceMana")) {
|
if (sa.hasParam("ReplaceMana")) {
|
||||||
@@ -79,31 +71,8 @@ public class ReplaceManaEffect extends SpellAbilityEffect {
|
|||||||
replaced = StringUtils.repeat(replaced, " ", Integer.valueOf(sa.getParam("ReplaceAmount")));
|
replaced = StringUtils.repeat(replaced, " ", Integer.valueOf(sa.getParam("ReplaceAmount")));
|
||||||
}
|
}
|
||||||
params.put(AbilityKey.Mana, replaced);
|
params.put(AbilityKey.Mana, replaced);
|
||||||
|
// effect was updated
|
||||||
// need to log Updated events there, or the log is wrong order
|
params.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.ability.AbilityUtils;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardZoneTable;
|
import forge.game.card.CardZoneTable;
|
||||||
import forge.game.card.token.TokenInfo;
|
|
||||||
import forge.game.event.GameEventCombatChanged;
|
import forge.game.event.GameEventCombatChanged;
|
||||||
import forge.game.event.GameEventTokenCreated;
|
import forge.game.event.GameEventTokenCreated;
|
||||||
import forge.game.player.Player;
|
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
|
|
||||||
public class TokenEffect extends TokenEffectBase {
|
public class TokenEffect extends TokenEffectBase {
|
||||||
@@ -36,20 +34,6 @@ public class TokenEffect extends TokenEffectBase {
|
|||||||
return sa.getDescription();
|
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
|
@Override
|
||||||
public void resolve(SpellAbility sa) {
|
public void resolve(SpellAbility sa) {
|
||||||
final Card host = sa.getHostCard();
|
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);
|
final int finalAmount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("TokenAmount", "1"), sa);
|
||||||
|
MutableBoolean combatChanged = new MutableBoolean(false);
|
||||||
|
|
||||||
boolean useZoneTable = true;
|
boolean useZoneTable = true;
|
||||||
CardZoneTable triggerList = sa.getChangeZoneTable();
|
CardZoneTable triggerList = sa.getChangeZoneTable();
|
||||||
@@ -82,10 +65,8 @@ public class TokenEffect extends TokenEffectBase {
|
|||||||
useZoneTable = true;
|
useZoneTable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MutableBoolean combatChanged = new MutableBoolean(false);
|
makeTokenTable(AbilityUtils.getDefinedPlayers(host, sa.getParamOrDefault("TokenOwner", "You"), sa),
|
||||||
for (final Player owner : AbilityUtils.getDefinedPlayers(host, sa.getParamOrDefault("TokenOwner", "You"), sa)) {
|
sa.getParam("TokenScript").split(","), finalAmount, false, triggerList, combatChanged, sa);
|
||||||
makeTokens(prototype, owner, sa, finalAmount, true, false, triggerList, combatChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!useZoneTable) {
|
if (!useZoneTable) {
|
||||||
triggerList.triggerChangesZoneAll(game, sa);
|
triggerList.triggerChangesZoneAll(game, sa);
|
||||||
|
|||||||
@@ -2,123 +2,202 @@ package forge.game.ability.effects;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.lang3.mutable.MutableBoolean;
|
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
import com.google.common.collect.Table;
|
||||||
|
|
||||||
import forge.GameCommand;
|
import forge.GameCommand;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.GameEntity;
|
import forge.game.GameEntity;
|
||||||
import forge.game.GameObject;
|
import forge.game.GameObject;
|
||||||
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollection;
|
import forge.game.card.CardCollection;
|
||||||
|
import forge.game.card.CardFactory;
|
||||||
import forge.game.card.CardUtil;
|
import forge.game.card.CardUtil;
|
||||||
import forge.game.card.CardZoneTable;
|
import forge.game.card.CardZoneTable;
|
||||||
import forge.game.card.CounterType;
|
import forge.game.card.CounterType;
|
||||||
|
import forge.game.card.TokenCreateTable;
|
||||||
import forge.game.card.token.TokenInfo;
|
import forge.game.card.token.TokenInfo;
|
||||||
import forge.game.event.GameEventCardStatsChanged;
|
import forge.game.event.GameEventCardStatsChanged;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
|
import forge.game.replacement.ReplacementType;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
|
|
||||||
public abstract class TokenEffectBase extends SpellAbilityEffect {
|
public abstract class TokenEffectBase extends SpellAbilityEffect {
|
||||||
|
|
||||||
protected List<Card> makeTokens(final Card prototype, final Player creator, final SpellAbility sa, int finalAmount,
|
protected TokenCreateTable createTokenTable(Iterable<Player> players, String[] tokenScripts, final int finalAmount, final SpellAbility sa) {
|
||||||
boolean applyMultiplier, boolean clone, CardZoneTable triggerList, MutableBoolean combatChanged) {
|
|
||||||
|
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 Card host = sa.getHostCard();
|
||||||
final Game game = host.getGame();
|
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();
|
final List<String> pumpKeywords = Lists.newArrayList();
|
||||||
if (sa.hasParam("PumpKeywords")) {
|
if (sa.hasParam("PumpKeywords")) {
|
||||||
pumpKeywords.addAll(Arrays.asList(sa.getParam("PumpKeywords").split(" & ")));
|
pumpKeywords.addAll(Arrays.asList(sa.getParam("PumpKeywords").split(" & ")));
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Card> allTokens = Lists.newArrayList();
|
List<Card> allTokens = Lists.newArrayList();
|
||||||
for (Card tok : TokenInfo.makeTokensFromPrototype(prototype, creator, finalAmount, applyMultiplier)) {
|
for (final Table.Cell<Player, Card, Integer> c : tokenTable.cellSet()) {
|
||||||
if (sa.hasParam("TokenTapped")) {
|
Card prototype = c.getColumnKey();
|
||||||
tok.setTapped(true);
|
Player creator = c.getRowKey();
|
||||||
}
|
Player controller = prototype.getController();
|
||||||
|
int cellAmount = c.getValue();
|
||||||
if (!sa.hasParam("AttachAfter") && sa.hasParam("AttachedTo") && !attachTokenTo(tok, sa)) {
|
for (int i = 0; i < cellAmount; i++) {
|
||||||
continue;
|
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
|
||||||
if (sa.hasParam("WithCounters")) {
|
tok.setOwner(creator);
|
||||||
String[] parse = sa.getParam("WithCounters").split("_");
|
if (creator != controller) {
|
||||||
tok.addEtbCounter(CounterType.getType(parse[0]), Integer.parseInt(parse[1]), creator);
|
tok.setController(controller, timestamp);
|
||||||
}
|
|
||||||
|
|
||||||
if (sa.hasParam("WithCountersType")) {
|
|
||||||
CounterType cType = CounterType.getType(sa.getParam("WithCountersType"));
|
|
||||||
int cAmount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("WithCountersAmount", "1"), sa);
|
|
||||||
tok.addEtbCounter(cType, cAmount, creator);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clone) {
|
|
||||||
tok.setCopiedPermanent(prototype);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should this be catching the Card that's returned?
|
|
||||||
Card c = game.getAction().moveToPlay(tok, sa);
|
|
||||||
if (c == null || c.getZone() == null) {
|
|
||||||
// in case token can't enter the battlefield, it isn't created
|
|
||||||
triggerList.put(ZoneType.None, ZoneType.None, c);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
triggerList.put(ZoneType.None, c.getZone().getZoneType(), c);
|
|
||||||
|
|
||||||
creator.addTokensCreatedThisTurn();
|
|
||||||
|
|
||||||
if (clone) {
|
|
||||||
c.setCloneOrigin(host);
|
|
||||||
}
|
|
||||||
if (!pumpKeywords.isEmpty()) {
|
|
||||||
c.addChangedCardKeywords(pumpKeywords, Lists.newArrayList(), false, false, timestamp);
|
|
||||||
addPumpUntil(sa, c, timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sa.hasParam("AtEOTTrig")) {
|
|
||||||
addSelfTrigger(sa, sa.getParam("AtEOTTrig"), c);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addToCombat(c, tok.getController(), sa, "TokenAttacking", "TokenBlocking")) {
|
|
||||||
combatChanged.setTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sa.hasParam("AttachAfter") && sa.hasParam("AttachedTo")) {
|
|
||||||
attachTokenTo(tok, sa);
|
|
||||||
}
|
|
||||||
|
|
||||||
c.updateStateForView();
|
|
||||||
|
|
||||||
if (sa.hasParam("RememberTokens")) {
|
|
||||||
host.addRemembered(c);
|
|
||||||
}
|
|
||||||
if (sa.hasParam("ImprintTokens")) {
|
|
||||||
host.addImprintedCard(c);
|
|
||||||
}
|
|
||||||
if (sa.hasParam("RememberSource")) {
|
|
||||||
c.addRemembered(host);
|
|
||||||
}
|
|
||||||
if (sa.hasParam("TokenRemembered")) {
|
|
||||||
final String remembered = sa.getParam("TokenRemembered");
|
|
||||||
for (final Object o : AbilityUtils.getDefinedObjects(host, remembered, sa)) {
|
|
||||||
c.addRemembered(o);
|
|
||||||
}
|
}
|
||||||
|
tok.setTimestamp(timestamp);
|
||||||
|
tok.setToken(true);
|
||||||
|
|
||||||
|
// do effect stuff with the token
|
||||||
|
if (sa.hasParam("TokenTapped")) {
|
||||||
|
tok.setTapped(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sa.hasParam("WithCountersType")) {
|
||||||
|
CounterType cType = CounterType.getType(sa.getParam("WithCountersType"));
|
||||||
|
int cAmount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("WithCountersAmount", "1"), sa);
|
||||||
|
tok.addEtbCounter(cType, cAmount, creator);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clone) {
|
||||||
|
tok.setCopiedPermanent(prototype);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should this be catching the Card that's returned?
|
||||||
|
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, moved);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
triggerList.put(ZoneType.None, moved.getZone().getZoneType(), moved);
|
||||||
|
|
||||||
|
creator.addTokensCreatedThisTurn();
|
||||||
|
|
||||||
|
if (clone) {
|
||||||
|
moved.setCloneOrigin(host);
|
||||||
|
}
|
||||||
|
if (!pumpKeywords.isEmpty()) {
|
||||||
|
moved.addChangedCardKeywords(pumpKeywords, Lists.newArrayList(), false, false, timestamp);
|
||||||
|
addPumpUntil(sa, moved, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sa.hasParam("AtEOTTrig")) {
|
||||||
|
addSelfTrigger(sa, sa.getParam("AtEOTTrig"), moved);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addToCombat(moved, tok.getController(), sa, "TokenAttacking", "TokenBlocking")) {
|
||||||
|
combatChanged.setTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sa.hasParam("AttachAfter") && sa.hasParam("AttachedTo")) {
|
||||||
|
attachTokenTo(tok, sa);
|
||||||
|
}
|
||||||
|
|
||||||
|
moved.updateStateForView();
|
||||||
|
|
||||||
|
if (sa.hasParam("RememberTokens")) {
|
||||||
|
host.addRemembered(moved);
|
||||||
|
}
|
||||||
|
if (sa.hasParam("ImprintTokens")) {
|
||||||
|
host.addImprintedCard(moved);
|
||||||
|
}
|
||||||
|
if (sa.hasParam("RememberSource")) {
|
||||||
|
moved.addRemembered(host);
|
||||||
|
}
|
||||||
|
if (sa.hasParam("TokenRemembered")) {
|
||||||
|
final String remembered = sa.getParam("TokenRemembered");
|
||||||
|
for (final Object o : AbilityUtils.getDefinedObjects(host, remembered, sa)) {
|
||||||
|
moved.addRemembered(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
allTokens.add(moved);
|
||||||
}
|
}
|
||||||
allTokens.add(c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sa.hasParam("AtEOT")) {
|
if (sa.hasParam("AtEOT")) {
|
||||||
registerDelayedTrigger(sa, sa.getParam("AtEOT"), allTokens);
|
registerDelayedTrigger(sa, sa.getParam("AtEOT"), allTokens);
|
||||||
}
|
}
|
||||||
return allTokens;
|
return tokenTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean attachTokenTo(Card tok, SpellAbility sa) {
|
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.CardType;
|
||||||
import forge.card.MagicColor;
|
import forge.card.MagicColor;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.ability.AbilityKey;
|
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardFactory;
|
|
||||||
import forge.game.card.CardFactoryUtil;
|
import forge.game.card.CardFactoryUtil;
|
||||||
import forge.game.card.CardUtil;
|
import forge.game.card.CardUtil;
|
||||||
import forge.game.keyword.KeywordInterface;
|
import forge.game.keyword.KeywordInterface;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.replacement.ReplacementType;
|
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.item.PaperToken;
|
import forge.item.PaperToken;
|
||||||
|
|
||||||
@@ -140,59 +137,6 @@ public class TokenInfo {
|
|||||||
return sb.toString();
|
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) {
|
public Card makeOneToken(final Player controller) {
|
||||||
final Game game = controller.getGame();
|
final Game game = controller.getGame();
|
||||||
final Card c = toCard(game);
|
final Card c = toCard(game);
|
||||||
@@ -321,10 +265,10 @@ public class TokenInfo {
|
|||||||
result.getCurrentState().changeTextIntrinsic(colorMap, typeMap);
|
result.getCurrentState().changeTextIntrinsic(colorMap, typeMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static public Card getProtoType(final String script, final SpellAbility sa) {
|
static public Card getProtoType(final String script, final SpellAbility sa, final Player owner) {
|
||||||
return getProtoType(script, sa, true);
|
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
|
// script might be null, or sa might be null
|
||||||
if (script == null || sa == null) {
|
if (script == null || sa == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -338,7 +282,7 @@ public class TokenInfo {
|
|||||||
if (token == null) {
|
if (token == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final Card result = Card.fromPaperCard(token, null, game);
|
final Card result = Card.fromPaperCard(token, owner, game);
|
||||||
|
|
||||||
if (sa.hasParam("TokenPower")) {
|
if (sa.hasParam("TokenPower")) {
|
||||||
String str = sa.getParam("TokenPower");
|
String str = sa.getParam("TokenPower");
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import java.util.Map;
|
|||||||
|
|
||||||
import forge.game.ability.AbilityKey;
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
|
import forge.game.card.TokenCreateTable;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,9 +28,11 @@ public class ReplaceToken extends ReplacementEffect {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||||
|
/*
|
||||||
if (((int) runParams.get(AbilityKey.TokenNum)) <= 0) {
|
if (((int) runParams.get(AbilityKey.TokenNum)) <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
//*/
|
||||||
|
|
||||||
if (hasParam("EffectOnly")) {
|
if (hasParam("EffectOnly")) {
|
||||||
final Boolean effectOnly = (Boolean) runParams.get(AbilityKey.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))) {
|
if (!matchesValidParam("ValidPlayer", runParams.get(AbilityKey.Affected))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*/
|
||||||
if (!matchesValidParam("ValidToken", runParams.get(AbilityKey.Token))) {
|
if (!matchesValidParam("ValidToken", runParams.get(AbilityKey.Token))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
//*/
|
||||||
|
|
||||||
|
if (filterAmount((TokenCreateTable) runParams.get(AbilityKey.Token)) <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -54,8 +63,13 @@ public class ReplaceToken extends ReplacementEffect {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
|
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));
|
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 org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import forge.game.CardTraitBase;
|
import forge.game.CardTraitBase;
|
||||||
@@ -274,20 +275,45 @@ public class ReplacementHandler {
|
|||||||
chosenRE.setOtherChoices(null);
|
chosenRE.setOtherChoices(null);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log there
|
||||||
|
String message = chosenRE.getDescription();
|
||||||
|
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);
|
chosenRE.setHasRun(false);
|
||||||
hasRun.remove(chosenRE);
|
hasRun.remove(chosenRE);
|
||||||
chosenRE.setOtherChoices(null);
|
chosenRE.setOtherChoices(null);
|
||||||
|
|
||||||
// Updated Replacements need to be logged elsewhere because its otherwise in the wrong order
|
|
||||||
if (res != ReplacementResult.Updated) {
|
|
||||||
String message = chosenRE.getDescription();
|
|
||||||
if (!StringUtils.isEmpty(message))
|
|
||||||
if (chosenRE.getHostCard() != null) {
|
|
||||||
message = TextUtil.fastReplace(message, "CARDNAME", chosenRE.getHostCard().getName());
|
|
||||||
}
|
|
||||||
game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,7 +326,6 @@ public class ReplacementHandler {
|
|||||||
*/
|
*/
|
||||||
private ReplacementResult executeReplacement(final Map<AbilityKey, Object> runParams,
|
private ReplacementResult executeReplacement(final Map<AbilityKey, Object> runParams,
|
||||||
final ReplacementEffect replacementEffect, final Player decider, final Game game) {
|
final ReplacementEffect replacementEffect, final Player decider, final Game game) {
|
||||||
final Map<String, String> mapParams = replacementEffect.getMapParams();
|
|
||||||
|
|
||||||
SpellAbility effectSA = null;
|
SpellAbility effectSA = null;
|
||||||
|
|
||||||
@@ -311,10 +336,9 @@ public class ReplacementHandler {
|
|||||||
host = game.getCardState(host);
|
host = game.getCardState(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (replacementEffect.getOverridingAbility() == null && mapParams.containsKey("ReplaceWith")) {
|
if (replacementEffect.getOverridingAbility() == null && replacementEffect.hasParam("ReplaceWith")) {
|
||||||
final String effectSVar = mapParams.get("ReplaceWith");
|
|
||||||
// TODO: the source of replacement effect should be the source of the original effect
|
// 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);
|
//replacementEffect.setOverridingAbility(effectSA);
|
||||||
//effectSA.setTrigger(true);
|
//effectSA.setTrigger(true);
|
||||||
} else if (replacementEffect.getOverridingAbility() != null) {
|
} else if (replacementEffect.getOverridingAbility() != null) {
|
||||||
@@ -342,10 +366,10 @@ public class ReplacementHandler {
|
|||||||
// Decider gets to choose whether or not to apply the replacement.
|
// Decider gets to choose whether or not to apply the replacement.
|
||||||
if (replacementEffect.hasParam("Optional")) {
|
if (replacementEffect.hasParam("Optional")) {
|
||||||
Player optDecider = decider;
|
Player optDecider = decider;
|
||||||
if (mapParams.containsKey("OptionalDecider") && (effectSA != null)) {
|
if (replacementEffect.hasParam("OptionalDecider") && (effectSA != null)) {
|
||||||
effectSA.setActivatingPlayer(host.getController());
|
effectSA.setActivatingPlayer(host.getController());
|
||||||
optDecider = AbilityUtils.getDefinedPlayers(host,
|
optDecider = AbilityUtils.getDefinedPlayers(host,
|
||||||
mapParams.get("OptionalDecider"), effectSA).get(0);
|
replacementEffect.getParam("OptionalDecider"), effectSA).get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Card cardForUi = host.getCardForUi();
|
Card cardForUi = host.getCardForUi();
|
||||||
@@ -360,12 +384,12 @@ public class ReplacementHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isPrevent = mapParams.containsKey("Prevent") && mapParams.get("Prevent").equals("True");
|
boolean isPrevent = "True".equals(replacementEffect.getParam("Prevent"));
|
||||||
if (isPrevent || mapParams.containsKey("PreventionEffect")) {
|
if (isPrevent || replacementEffect.hasParam("PreventionEffect")) {
|
||||||
if (Boolean.TRUE.equals(runParams.get(AbilityKey.NoPreventDamage))) {
|
if (Boolean.TRUE.equals(runParams.get(AbilityKey.NoPreventDamage))) {
|
||||||
// If can't prevent damage, result is not replaced
|
// If can't prevent damage, result is not replaced
|
||||||
// But still put "prevented" amount for buffered SA
|
// But still put "prevented" amount for buffered SA
|
||||||
if (mapParams.containsKey("AlwaysReplace")) {
|
if (replacementEffect.hasParam("AlwaysReplace")) {
|
||||||
runParams.put(AbilityKey.PreventedAmount, runParams.get(AbilityKey.DamageAmount));
|
runParams.put(AbilityKey.PreventedAmount, runParams.get(AbilityKey.DamageAmount));
|
||||||
} else {
|
} else {
|
||||||
runParams.put(AbilityKey.PreventedAmount, 0);
|
runParams.put(AbilityKey.PreventedAmount, 0);
|
||||||
@@ -377,10 +401,8 @@ public class ReplacementHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mapParams.containsKey("Skip")) {
|
if ("True".equals(replacementEffect.getParam("Skip"))) {
|
||||||
if (mapParams.get("Skip").equals("True")) {
|
return ReplacementResult.Skipped; // Event is skipped.
|
||||||
return ReplacementResult.Skipped; // Event is skipped.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Player player = host.getController();
|
Player player = host.getController();
|
||||||
@@ -394,6 +416,11 @@ public class ReplacementHandler {
|
|||||||
// The SA if buffered, but replacement result should be set to Replaced
|
// The SA if buffered, but replacement result should be set to Replaced
|
||||||
runParams.put(AbilityKey.ReplacementResult, ReplacementResult.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
|
// if the spellability is a replace effect then its some new logic
|
||||||
|
|||||||
@@ -2,11 +2,8 @@ Name:Academy Manufactor
|
|||||||
ManaCost:3
|
ManaCost:3
|
||||||
Types:Artifact Creature Assembly-Worker
|
Types:Artifact Creature Assembly-Worker
|
||||||
PT:1/3
|
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.
|
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:DBToken:DB$ Token | TokenScript$ c_a_clue_draw | TokenAmount$ X | SubAbility$ DBToken2
|
SVar:TokenReplace:DB$ ReplaceToken | Type$ ReplaceToken | ValidCard$ Clue,Food,Treasure | TokenScript$ c_a_clue_draw,c_a_food_sac,c_a_treasure_sac
|
||||||
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
|
|
||||||
DeckHas:Ability$Sacrifice & Ability$Token & Ability$LifeGain
|
DeckHas:Ability$Sacrifice & Ability$Token & Ability$LifeGain
|
||||||
DeckHints:Ability$Investigate
|
DeckHints:Ability$Investigate
|
||||||
Oracle:If you would create a Clue, Food, or Treasure token, instead create one of each.
|
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
|
Types:Legendary Creature Merfolk Wizard
|
||||||
PT:2/2
|
PT:2/2
|
||||||
K:Ward: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.
|
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$ ReplaceEffect | VarName$ TokenNum | VarValue$ X
|
SVar:DoubleToken:DB$ ReplaceToken | Type$ Amount | ValidCard$ Card.YouCtrl
|
||||||
SVar:X:ReplaceCount$TokenNum/Twice
|
|
||||||
DeckHints:Ability$Token
|
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.
|
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
|
Name:Anointed Procession
|
||||||
ManaCost:3 W
|
ManaCost:3 W
|
||||||
Types:Enchantment
|
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.
|
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$ ReplaceEffect | VarName$ TokenNum | VarValue$ X
|
SVar:DoubleToken:DB$ ReplaceToken | Type$ Amount | ValidCard$ Card.YouCtrl
|
||||||
SVar:X:ReplaceCount$TokenNum/Twice
|
|
||||||
DeckNeeds:Ability$Token
|
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.
|
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
|
Name:Bestial Menace
|
||||||
ManaCost:3 G G
|
ManaCost:3 G G
|
||||||
Types:Sorcery
|
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,
|
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.
|
||||||
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
|
|
||||||
Oracle: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
|
Types:Legendary Creature Squirrel Warrior
|
||||||
PT:3/3
|
PT:3/3
|
||||||
K:Forestwalk
|
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.
|
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$ ReplaceEffect | VarName$ TokenNum | VarValue$ Y | SubAbility$ DBToken
|
SVar:DBReplace:DB$ ReplaceToken | Type$ AddToken | ValidCard$ Card.YouCtrl | TokenScript$ g_1_1_squirrel
|
||||||
SVar:DBToken:DB$ Token | TokenAmount$ Y | 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.
|
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:X:Count$xPaid
|
||||||
SVar:Y:ReplaceCount$TokenNum
|
|
||||||
DeckHas:Ability$Token
|
DeckHas:Ability$Token
|
||||||
DeckHints:Type$Squirrel
|
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.
|
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
|
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.
|
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: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: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$ ReplaceEffect | VarName$ Affected | VarValue$ You | VarType$ Player
|
SVar:ETBYourCtrl:DB$ ReplaceToken | Type$ ReplaceController | ValidCard$ Card.OppCtrl | NewController$ You
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/crafty_cutpurse.jpg
|
|
||||||
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.
|
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
|
Name:Divine Visitation
|
||||||
ManaCost:3 W W
|
ManaCost:3 W W
|
||||||
Types:Enchantment
|
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.
|
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$ ReplaceEffect | VarName$ Token | VarValue$ w_4_4_angel_flying_vigilance | VarType$ TokenScript
|
SVar:TokenReplace:DB$ ReplaceToken | Type$ ReplaceToken | ValidCard$ Creature.YouCtrl | TokenScript$ w_4_4_angel_flying_vigilance
|
||||||
DeckNeeds:Ability$Token
|
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.
|
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
|
Name:Doubling Season
|
||||||
ManaCost:4 G
|
ManaCost:4 G
|
||||||
Types:Enchantment
|
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.
|
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$ ReplaceEffect | VarName$ TokenNum | VarValue$ X
|
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.
|
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:DoubleCounters:DB$ ReplaceEffect | VarName$ CounterNum | VarValue$ Y
|
||||||
SVar:X:ReplaceCount$TokenNum/Twice
|
|
||||||
SVar:Y:ReplaceCount$CounterNum/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.
|
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
|
Name:Forbidden Friendship
|
||||||
ManaCost:1 R
|
ManaCost:1 R
|
||||||
Types:Sorcery
|
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.
|
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.
|
||||||
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
|
|
||||||
DeckHas:Ability$Token
|
DeckHas:Ability$Token
|
||||||
Oracle:Create a 1/1 red Dinosaur creature token with haste and a 1/1 white Human Soldier creature 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
|
Name:Mascot Exhibition
|
||||||
ManaCost:7
|
ManaCost:7
|
||||||
Types:Sorcery Lesson
|
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,
|
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.
|
||||||
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
|
|
||||||
DeckHas:Ability$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.
|
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
|
Name:Parallel Lives
|
||||||
ManaCost:3 G
|
ManaCost:3 G
|
||||||
Types:Enchantment
|
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.
|
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$ ReplaceEffect | VarName$ TokenNum | VarValue$ X
|
SVar:DoubleToken:DB$ ReplaceToken | Type$ Amount | ValidCard$ Card.YouCtrl
|
||||||
SVar:X:ReplaceCount$TokenNum/Twice
|
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/parallel_lives.jpg
|
|
||||||
Oracle:If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead.
|
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
|
Name:Primal Vigor
|
||||||
ManaCost:4 G
|
ManaCost:4 G
|
||||||
Types:Enchantment
|
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.
|
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$ ReplaceEffect | VarName$ TokenNum | VarValue$ X
|
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.
|
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:DoubleP1P1Counters:DB$ ReplaceEffect | VarName$ CounterNum | VarValue$ Y
|
||||||
SVar:X:ReplaceCount$TokenNum/Twice
|
|
||||||
SVar:Y:ReplaceCount$CounterNum/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.
|
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
|
ManaCost:no cost
|
||||||
Types:Plane Ravnica
|
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.
|
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.
|
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:DoubleCounters:DB$ ReplaceEffect | VarName$ CounterNum | VarValue$ Z
|
||||||
SVar:Y:ReplaceCount$TokenNum/Twice
|
|
||||||
SVar:Z:ReplaceCount$CounterNum/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.
|
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
|
SVar:RolledChaos:DB$ Effect | AILogic$ Always | Triggers$ TrigTapForMana
|
||||||
|
|||||||
@@ -3,9 +3,7 @@ ManaCost:4 U
|
|||||||
Types:Creature Vedalken Wizard
|
Types:Creature Vedalken Wizard
|
||||||
PT:2/1
|
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.
|
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:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ g_1_1_squirrel,u_0_3_crab | TokenOwner$ You
|
||||||
SVar:DBCrabToken:DB$ Token | TokenAmount$ 1 | TokenScript$ u_0_3_crab | TokenOwner$ You | SubAbility$ DBResolve
|
|
||||||
SVar:DBResolve:DB$ ChangeZoneResolve
|
|
||||||
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.
|
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
|
SVar:TrigCopy:DB$ CopyPermanent | ValidTgts$ Permanent.token+YouCtrl | TgtPrompt$ Select target token you control
|
||||||
DeckHas:Ability$Token
|
DeckHas:Ability$Token
|
||||||
|
|||||||
@@ -5,10 +5,7 @@ PT:9/9
|
|||||||
K:Flying
|
K:Flying
|
||||||
K:Vigilance
|
K:Vigilance
|
||||||
K:Trample
|
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.
|
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:TrigTokenFly:DB$Token | TokenAmount$ 1 | TokenScript$ c_3_3_a_golem_flying | ChangeZoneTable$ True | SubAbility$ DBTokenVig
|
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
|
||||||
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
|
|
||||||
DeckHas:Ability$Token
|
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.
|
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
|
ManaCost:2 R
|
||||||
Types:Creature Elemental
|
Types:Creature Elemental
|
||||||
PT:3/2
|
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.
|
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:AdditionalToken:DB$ ReplaceEffect | VarName$ TokenNum | VarValue$ X
|
SVar:DBReplace:DB$ ReplaceToken | Type$ AddToken | Amount$ 1 | TokenScript$ c_a_treasure_sac
|
||||||
SVar:X:ReplaceCount$TokenNum/Plus.1
|
|
||||||
DeckNeeds:Type$Token
|
DeckNeeds:Type$Token
|
||||||
AI:RemoveDeck:Random
|
AI:RemoveDeck:Random
|
||||||
Oracle:If you would create one or more Treasure tokens, instead create those tokens plus an additional Treasure token.
|
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")) {
|
if (sa.hasParam("TokenScript")) {
|
||||||
sa.setActivatingPlayer(player);
|
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()) {
|
for (String type : protoType.getType().getCreatureTypes()) {
|
||||||
Integer count = typesInDeck.get(type);
|
Integer count = typesInDeck.get(type);
|
||||||
if (count == null) {
|
if (count == null) {
|
||||||
@@ -1340,7 +1340,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
|||||||
if (sa != null) {
|
if (sa != null) {
|
||||||
if (sa.hasParam("TokenScript")) {
|
if (sa.hasParam("TokenScript")) {
|
||||||
sa.setActivatingPlayer(player);
|
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()) {
|
for (String type : protoType.getType().getCreatureTypes()) {
|
||||||
Integer count = typesInDeck.get(type);
|
Integer count = typesInDeck.get(type);
|
||||||
if (count == null) {
|
if (count == null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user