mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 18:58:00 +00:00
Compare commits
17 Commits
forge-2.0.
...
exiledWith
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25b6db1536 | ||
|
|
245586cefa | ||
|
|
21999488f4 | ||
|
|
d8b9524f80 | ||
|
|
3bda4ffe0a | ||
|
|
4dba174a6c | ||
|
|
f57f6e1c40 | ||
|
|
c9c974ad00 | ||
|
|
18be2c67b6 | ||
|
|
c27fa18ed7 | ||
|
|
fb7a212597 | ||
|
|
c05f2396a1 | ||
|
|
0ac7fb59e6 | ||
|
|
1db6a772ed | ||
|
|
d12527ff21 | ||
|
|
ab5eb24d7a | ||
|
|
9f5fd3f35f |
@@ -6,10 +6,9 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.card.CardType;
|
||||
@@ -59,6 +58,7 @@ import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityStackInstance;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.Localizer;
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.collect.FCollectionView;
|
||||
|
||||
@@ -92,9 +92,15 @@ public class AiCostDecision extends CostDecisionMakerBase {
|
||||
|
||||
@Override
|
||||
public PaymentDecision visit(CostChooseCreatureType cost) {
|
||||
String choice = player.getController().chooseSomeType("Creature", ability, CardType.getAllCreatureTypes(),
|
||||
Lists.newArrayList());
|
||||
return PaymentDecision.type(choice);
|
||||
Integer amount = cost.convertAmount();
|
||||
Iterable<String> choices = player.getController().chooseSomeType(
|
||||
Localizer.getInstance().getMessage("lblCreature"), ability, amount, amount, Lists.newArrayList(CardType.getAllCreatureTypes()));
|
||||
|
||||
if (choices == null || Iterables.isEmpty(choices)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return PaymentDecision.types(choices);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -601,7 +607,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
|
||||
public PaymentDecision visit(CostRemoveAnyCounter cost) {
|
||||
final String amount = cost.getAmount();
|
||||
final int c = AbilityUtils.calculateAmount(source, amount, ability);
|
||||
final Card originalHost = ObjectUtils.defaultIfNull(ability.getOriginalHost(), source);
|
||||
final Card originalHost = ability.getOriginalOrHost();
|
||||
|
||||
if (c <= 0) {
|
||||
return null;
|
||||
|
||||
@@ -2256,17 +2256,16 @@ public class ComputerUtil {
|
||||
return getCardsToDiscardFromOpponent(aiChooser, p, sa, validCards, min, max);
|
||||
}
|
||||
|
||||
public static String chooseSomeType(Player ai, String kindOfType, String logic, Collection<String> validTypes, List<String> invalidTypes) {
|
||||
if (invalidTypes == null) {
|
||||
invalidTypes = ImmutableList.of();
|
||||
}
|
||||
public static List<String> chooseSomeType(Player ai, String kindOfType, String logic, int min, int max, Collection<String> validTypes) {
|
||||
if (validTypes == null) {
|
||||
validTypes = ImmutableList.of();
|
||||
}
|
||||
|
||||
final Game game = ai.getGame();
|
||||
String chosen = "";
|
||||
List<String> chosenList = Lists.newArrayList();
|
||||
if (kindOfType.equals("Card")) {
|
||||
String chosen = "";
|
||||
|
||||
// TODO
|
||||
// computer will need to choose a type
|
||||
// based on whether it needs a creature or land,
|
||||
@@ -2274,24 +2273,25 @@ public class ComputerUtil {
|
||||
// then, reveal chosenType to Human
|
||||
if (game.getPhaseHandler().is(PhaseType.UNTAP) && logic == null) { // Storage Matrix
|
||||
double amount = 0;
|
||||
for (String type : CardType.getAllCardTypes()) {
|
||||
if (!invalidTypes.contains(type)) {
|
||||
CardCollection list = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.isType(type), Presets.TAPPED);
|
||||
double i = type.equals("Creature") ? list.size() * 1.5 : list.size();
|
||||
if (i > amount) {
|
||||
amount = i;
|
||||
chosen = type;
|
||||
}
|
||||
for (String type : validTypes) {
|
||||
CardCollection list = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.isType(type), Presets.TAPPED);
|
||||
double i = type.equals("Creature") ? list.size() * 1.5 : list.size();
|
||||
if (i > amount) {
|
||||
amount = i;
|
||||
chosen = type;
|
||||
}
|
||||
}
|
||||
} else if (logic == "MostProminentInComputerDeck") {
|
||||
chosen = ComputerUtilCard.getMostProminentType(ai.getAllCards(), validTypes);
|
||||
}
|
||||
if (StringUtils.isEmpty(chosen)) {
|
||||
chosen = validTypes.isEmpty() ? "Creature" : Aggregates.random(validTypes);
|
||||
}
|
||||
chosenList.add(chosen);
|
||||
} else if (kindOfType.equals("Creature")) {
|
||||
String chosen = "";
|
||||
if (logic != null) {
|
||||
List <String> valid = Lists.newArrayList(CardType.getAllCreatureTypes());
|
||||
valid.removeAll(invalidTypes);
|
||||
List <String> valid = Lists.newArrayList(validTypes);
|
||||
|
||||
if (logic.equals("MostProminentOnBattlefield")) {
|
||||
chosen = ComputerUtilCard.getMostProminentType(game.getCardsIn(ZoneType.Battlefield), valid);
|
||||
@@ -2302,7 +2302,7 @@ public class ComputerUtil {
|
||||
else if (logic.equals("MostProminentOppControls")) {
|
||||
CardCollection list = CardLists.filterControlledBy(game.getCardsIn(ZoneType.Battlefield), ai.getOpponents());
|
||||
chosen = ComputerUtilCard.getMostProminentType(list, valid);
|
||||
if (!CardType.isACreatureType(chosen) || invalidTypes.contains(chosen)) {
|
||||
if (!CardType.isACreatureType(chosen) || !validTypes.contains(chosen)) {
|
||||
list = CardLists.filterControlledBy(game.getCardsInGame(), ai.getOpponents());
|
||||
chosen = ComputerUtilCard.getMostProminentType(list, valid);
|
||||
}
|
||||
@@ -2314,16 +2314,17 @@ public class ComputerUtil {
|
||||
chosen = ComputerUtilCard.getMostProminentType(ai.getCardsIn(ZoneType.Graveyard), valid);
|
||||
}
|
||||
}
|
||||
if (!CardType.isACreatureType(chosen) || invalidTypes.contains(chosen)) {
|
||||
chosen = "Sliver";
|
||||
if (!CardType.isACreatureType(chosen) || !validTypes.contains(chosen)) {
|
||||
chosen = Iterables.getFirst(validTypes, null);
|
||||
}
|
||||
|
||||
chosenList.add(chosen);
|
||||
} else if (kindOfType.equals("Basic Land")) {
|
||||
String chosen = "";
|
||||
if (logic != null) {
|
||||
if (logic.equals("MostProminentOppControls")) {
|
||||
CardCollection list = CardLists.filterControlledBy(game.getCardsIn(ZoneType.Battlefield), ai.getOpponents());
|
||||
List<String> valid = Lists.newArrayList(CardType.getBasicTypes());
|
||||
valid.removeAll(invalidTypes);
|
||||
List<String> valid = Lists.newArrayList(validTypes);
|
||||
|
||||
chosen = ComputerUtilCard.getMostProminentType(list, valid);
|
||||
} else if (logic.equals("MostNeededType")) {
|
||||
@@ -2346,9 +2347,9 @@ public class ComputerUtil {
|
||||
}
|
||||
}
|
||||
else if (logic.equals("ChosenLandwalk")) {
|
||||
for (Card c : ComputerUtil.getOpponentFor(ai).getLandsInPlay()) {
|
||||
for (Card c : ai.getWeakestOpponent().getLandsInPlay()) {
|
||||
for (String t : c.getType()) {
|
||||
if (!invalidTypes.contains(t) && CardType.isABasicLandType(t)) {
|
||||
if (validTypes.contains(t) && CardType.isABasicLandType(t)) {
|
||||
chosen = t;
|
||||
break;
|
||||
}
|
||||
@@ -2357,16 +2358,28 @@ public class ComputerUtil {
|
||||
}
|
||||
}
|
||||
|
||||
if (!CardType.isABasicLandType(chosen) || invalidTypes.contains(chosen)) {
|
||||
chosen = "Island";
|
||||
if (!CardType.isABasicLandType(chosen) || !validTypes.contains(chosen)) {
|
||||
chosen = Iterables.getFirst(validTypes, null);
|
||||
}
|
||||
chosenList.add(chosen);
|
||||
// the only one with choosing two types is Illusionary Terrain
|
||||
// and it needs other AI logic
|
||||
while (chosenList.size() < min) {
|
||||
validTypes.remove(chosen);
|
||||
chosen = Iterables.getFirst(validTypes, null);
|
||||
if (chosen == null) {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
chosenList.add(chosen);
|
||||
}
|
||||
}
|
||||
else if (kindOfType.equals("Land")) {
|
||||
String chosen = "";
|
||||
if (logic != null) {
|
||||
if (logic.equals("ChosenLandwalk")) {
|
||||
for (Card c : ComputerUtil.getOpponentFor(ai).getLandsInPlay()) {
|
||||
for (Card c : ai.getWeakestOpponent().getLandsInPlay()) {
|
||||
for (String t : c.getType().getLandTypes()) {
|
||||
if (!invalidTypes.contains(t)) {
|
||||
if (validTypes.contains(t)) {
|
||||
chosen = t;
|
||||
break;
|
||||
}
|
||||
@@ -2375,10 +2388,11 @@ public class ComputerUtil {
|
||||
}
|
||||
}
|
||||
if (StringUtils.isEmpty(chosen)) {
|
||||
chosen = "Island";
|
||||
chosen = Iterables.getFirst(validTypes, null);
|
||||
}
|
||||
chosenList.add(chosen);
|
||||
}
|
||||
return chosen;
|
||||
return chosenList;
|
||||
}
|
||||
|
||||
public static Object vote(Player ai, List<Object> options, SpellAbility sa, Multimap<Object, Player> votes, Player forPlayer) {
|
||||
|
||||
@@ -171,12 +171,8 @@ public class ComputerUtilAbility {
|
||||
return sa;
|
||||
}
|
||||
|
||||
public static Card getAbilitySource(SpellAbility sa) {
|
||||
return sa.getOriginalHost() != null ? sa.getOriginalHost() : sa.getHostCard();
|
||||
}
|
||||
|
||||
public static String getAbilitySourceName(SpellAbility sa) {
|
||||
final Card c = getAbilitySource(sa);
|
||||
final Card c = sa.getOriginalOrHost();
|
||||
return c != null ? c.getName() : "";
|
||||
}
|
||||
|
||||
|
||||
@@ -982,7 +982,7 @@ public class ComputerUtilCard {
|
||||
for(byte c : MagicColor.WUBRG) {
|
||||
String devotionCode = "Count$Devotion." + MagicColor.toLongString(c);
|
||||
|
||||
int devotion = CardFactoryUtil.xCount(sa.getHostCard(), devotionCode);
|
||||
int devotion = AbilityUtils.calculateAmount(sa.getHostCard(), devotionCode, sa);
|
||||
if (devotion > curDevotion && !CardLists.filter(hand, CardPredicates.isColor(c)).isEmpty()) {
|
||||
curDevotion = devotion;
|
||||
chosenColor = MagicColor.toLongString(c);
|
||||
|
||||
@@ -137,8 +137,9 @@ public class ComputerUtilCost {
|
||||
* the source
|
||||
* @return true, if successful
|
||||
*/
|
||||
|
||||
public static boolean checkDiscardCost(final Player ai, final Cost cost, final Card source, SpellAbility sa) {
|
||||
if (cost == null) {
|
||||
if (cost == null || source.hasSVar("AISkipDiscardCostCheck") /* FIXME: should not be needed! */ ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -319,8 +319,8 @@ public class ComputerUtilMana {
|
||||
|
||||
// Exception: when paying generic mana with Cavern of Souls, prefer the colored mana producing ability
|
||||
// to attempt to make the spell uncounterable when possible.
|
||||
if (ComputerUtilAbility.getAbilitySourceName(ma).equals("Cavern of Souls")
|
||||
&& sa.getHostCard().getType().getCreatureTypes().contains(ma.getHostCard().getChosenType())) {
|
||||
if (ComputerUtilAbility.getAbilitySourceName(ma).equals("Cavern of Souls") && ma.hasChosenType()
|
||||
&& sa.getHostCard().getType().getCreatureTypes().contains(ma.getChosenType(0))) {
|
||||
if (toPay == ManaCostShard.COLORLESS && cost.getUnpaidShards().contains(ManaCostShard.GENERIC)) {
|
||||
// Deprioritize Cavern of Souls, try to pay generic mana with it instead to use the NoCounter ability
|
||||
continue;
|
||||
@@ -414,7 +414,6 @@ public class ComputerUtilMana {
|
||||
// then apply this one
|
||||
if (!replaceType.isEmpty()) {
|
||||
for (SpellAbility saMana : replaceAmount) {
|
||||
Card card = saMana.getHostCard();
|
||||
if (saMana.hasParam("ReplaceType")) {
|
||||
// replace color and colorless
|
||||
String color = saMana.getParam("ReplaceType");
|
||||
@@ -436,8 +435,8 @@ public class ComputerUtilMana {
|
||||
// replace color
|
||||
String color = saMana.getParam("ReplaceColor");
|
||||
if ("Chosen".equals(color)) {
|
||||
if (card.hasChosenColor()) {
|
||||
color = MagicColor.toShortString(card.getChosenColor());
|
||||
if (saMana.hasChosenColor()) {
|
||||
color = MagicColor.toShortString(saMana.getChosenColor());
|
||||
}
|
||||
}
|
||||
if (saMana.hasParam("ReplaceOnly")) {
|
||||
@@ -489,7 +488,7 @@ public class ComputerUtilMana {
|
||||
int pAmount = AbilityUtils.calculateAmount(trSA.getHostCard(), trSA.getParamOrDefault("Amount", "1"), trSA);
|
||||
String produced = trSA.getParam("Produced");
|
||||
if (produced.equals("Chosen")) {
|
||||
produced = MagicColor.toShortString(trSA.getHostCard().getChosenColor());
|
||||
produced = MagicColor.toShortString(trSA.getHostCard().getChosenColor(trSA));
|
||||
}
|
||||
manaProduced += " " + StringUtils.repeat(produced, pAmount);
|
||||
} else if (ApiType.ManaReflected.equals(trSA.getApi())) {
|
||||
|
||||
@@ -89,8 +89,7 @@ public abstract class GameState {
|
||||
private final Map<Card, Integer> markedDamage = new HashMap<>();
|
||||
private final Map<Card, List<String>> cardToChosenClrs = new HashMap<>();
|
||||
private final Map<Card, CardCollection> cardToChosenCards = new HashMap<>();
|
||||
private final Map<Card, String> cardToChosenType = new HashMap<>();
|
||||
private final Map<Card, String> cardToChosenType2 = new HashMap<>();
|
||||
private final Map<Card, List<String>> cardToChosenTypes = new HashMap<>();
|
||||
private final Map<Card, List<String>> cardToRememberedId = new HashMap<>();
|
||||
private final Map<Card, List<String>> cardToImprintedId = new HashMap<>();
|
||||
private final Map<Card, List<String>> cardToMergedCards = new HashMap<>();
|
||||
@@ -341,15 +340,16 @@ public abstract class GameState {
|
||||
newText.append("|Damage:").append(c.getDamage());
|
||||
}
|
||||
|
||||
if (!c.getChosenColor().isEmpty()) {
|
||||
newText.append("|ChosenColor:").append(TextUtil.join(c.getChosenColors(), ","));
|
||||
}
|
||||
if (!c.getChosenType().isEmpty()) {
|
||||
newText.append("|ChosenType:").append(c.getChosenType());
|
||||
}
|
||||
if (!c.getChosenType2().isEmpty()) {
|
||||
newText.append("|ChosenType2:").append(c.getChosenType2());
|
||||
SpellAbility first = c.getFirstSpellAbility();
|
||||
if (first != null) {
|
||||
if (first.hasChosenColor()) {
|
||||
newText.append("|ChosenColor:").append(TextUtil.join(first.getChosenColors(), ","));
|
||||
}
|
||||
if (first.hasChosenType()) {
|
||||
newText.append("|ChosenType:").append(TextUtil.join(first.getChosenType(), ","));
|
||||
}
|
||||
}
|
||||
|
||||
if (!c.getNamedCard().isEmpty()) {
|
||||
newText.append("|NamedCard:").append(c.getNamedCard());
|
||||
}
|
||||
@@ -638,8 +638,7 @@ public abstract class GameState {
|
||||
markedDamage.clear();
|
||||
cardToChosenClrs.clear();
|
||||
cardToChosenCards.clear();
|
||||
cardToChosenType.clear();
|
||||
cardToChosenType2.clear();
|
||||
cardToChosenTypes.clear();
|
||||
cardToMergedCards.clear();
|
||||
cardToScript.clear();
|
||||
cardAttackMap.clear();
|
||||
@@ -734,7 +733,7 @@ public abstract class GameState {
|
||||
if (persistent) {
|
||||
produced.put("PersistentMana", "True");
|
||||
}
|
||||
final AbilityManaPart abMana = new AbilityManaPart(dummy, produced);
|
||||
final AbilityManaPart abMana = new AbilityManaPart(dummy, null, produced);
|
||||
game.getAction().invoke(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -829,6 +828,7 @@ public abstract class GameState {
|
||||
Card exiledWith = idToCard.get(Integer.parseInt(id));
|
||||
c.setExiledWith(exiledWith);
|
||||
c.setExiledBy(exiledWith.getController());
|
||||
exiledWith.addExiledWith(c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1087,19 +1087,13 @@ public abstract class GameState {
|
||||
Card c = entry.getKey();
|
||||
List<String> colors = entry.getValue();
|
||||
|
||||
c.setChosenColors(colors);
|
||||
c.setChosenColors(colors, c.getFirstSpellAbility());
|
||||
}
|
||||
|
||||
// Chosen type
|
||||
for (Entry<Card, String> entry : cardToChosenType.entrySet()) {
|
||||
for (Entry<Card, List<String>> entry : cardToChosenTypes.entrySet()) {
|
||||
Card c = entry.getKey();
|
||||
c.setChosenType(entry.getValue());
|
||||
}
|
||||
|
||||
// Chosen type 2
|
||||
for (Entry<Card, String> entry : cardToChosenType2.entrySet()) {
|
||||
Card c = entry.getKey();
|
||||
c.setChosenType2(entry.getValue());
|
||||
c.setChosenType(entry.getValue(), c.getFirstSpellAbility());
|
||||
}
|
||||
|
||||
// Named card
|
||||
@@ -1385,9 +1379,7 @@ public abstract class GameState {
|
||||
} else if (info.startsWith("ChosenColor:")) {
|
||||
cardToChosenClrs.put(c, Arrays.asList(info.substring(info.indexOf(':') + 1).split(",")));
|
||||
} else if (info.startsWith("ChosenType:")) {
|
||||
cardToChosenType.put(c, info.substring(info.indexOf(':') + 1));
|
||||
} else if (info.startsWith("ChosenType2:")) {
|
||||
cardToChosenType2.put(c, info.substring(info.indexOf(':') + 1));
|
||||
cardToChosenTypes.put(c, Arrays.asList(info.substring(info.indexOf(':') + 1).split(",")));
|
||||
} else if (info.startsWith("ChosenCards:")) {
|
||||
CardCollection chosen = new CardCollection();
|
||||
String[] idlist = info.substring(info.indexOf(':') + 1).split(",");
|
||||
|
||||
@@ -8,7 +8,6 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
@@ -80,7 +79,6 @@ import forge.util.MyRandom;
|
||||
import forge.util.collect.FCollection;
|
||||
import forge.util.collect.FCollectionView;
|
||||
|
||||
|
||||
/**
|
||||
* A prototype for player controller class
|
||||
*
|
||||
@@ -545,13 +543,12 @@ public class PlayerControllerAi extends PlayerController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseSomeType(String kindOfType, SpellAbility sa, Collection<String> validTypes, List<String> invalidTypes, boolean isOptional) {
|
||||
String chosen = ComputerUtil.chooseSomeType(player, kindOfType, sa.getParam("AILogic"), validTypes, invalidTypes);
|
||||
if (StringUtils.isBlank(chosen) && !validTypes.isEmpty()) {
|
||||
chosen = validTypes.iterator().next();
|
||||
System.err.println("AI has no idea how to choose " + kindOfType +", defaulting to arbitrary element: chosen");
|
||||
public List<String> chooseSomeType(String kindOfType, SpellAbility sa, int min, int max, List<String> validTypes) {
|
||||
List<String> chosen = ComputerUtil.chooseSomeType(player, kindOfType, sa.getParam("AILogic"), min, max, validTypes);
|
||||
if (chosen.isEmpty()) {
|
||||
return validTypes.subList(0, min);
|
||||
}
|
||||
getGame().getAction().notifyOfValue(sa, player, chosen, player);
|
||||
getGame().getAction().notifyOfValue(sa, player, chosen.toString(), player);
|
||||
return chosen;
|
||||
}
|
||||
|
||||
|
||||
@@ -1000,7 +1000,7 @@ public class SpecialCardAi {
|
||||
return false;
|
||||
}
|
||||
String prominentColor = ComputerUtilCard.getMostProminentColor(ai.getCardsIn(ZoneType.Battlefield));
|
||||
int devotion = CardFactoryUtil.xCount(sa.getHostCard(), "Count$Devotion." + prominentColor);
|
||||
int devotion = AbilityUtils.calculateAmount(sa.getHostCard(), "Count$Devotion." + prominentColor, sa);
|
||||
int activationCost = sa.getPayCosts().getTotalMana().getCMC() + (sa.getPayCosts().hasTapCost() ? 1 : 0);
|
||||
|
||||
// do not use this SA if devotion to most prominent color is less than its own activation cost + 1 (to actually get advantage)
|
||||
|
||||
@@ -401,7 +401,7 @@ public class AnimateAi extends SpellAbilityAi {
|
||||
// allow ChosenType - overrides anything else specified
|
||||
if (types.hasSubtype("ChosenType")) {
|
||||
types.clear();
|
||||
types.add(source.getChosenType());
|
||||
types.addAll(sa.getChosenType());
|
||||
}
|
||||
|
||||
final List<String> keywords = Lists.newArrayList();
|
||||
@@ -432,7 +432,7 @@ public class AnimateAi extends SpellAbilityAi {
|
||||
if (sa.hasParam("Colors")) {
|
||||
final String colors = sa.getParam("Colors");
|
||||
if (colors.equals("ChosenColor")) {
|
||||
tmpDesc = CardUtil.getShortColorsString(source.getChosenColors());
|
||||
tmpDesc = CardUtil.getShortColorsString(sa.getChosenColors());
|
||||
} else {
|
||||
tmpDesc = CardUtil.getShortColorsString(Lists.newArrayList(Arrays.asList(colors.split(","))));
|
||||
}
|
||||
|
||||
@@ -74,9 +74,11 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
|
||||
@Override
|
||||
protected boolean checkAiLogic(final Player ai, final SpellAbility sa, final String aiLogic) {
|
||||
if (sa.getHostCard() != null && sa.getHostCard().hasSVar("AIPreferenceOverride")) {
|
||||
Card host = sa.getHostCard();
|
||||
|
||||
if (host != null && host.hasSVar("AIPreferenceOverride")) {
|
||||
// currently used by SacAndUpgrade logic, might need simplification
|
||||
sa.getHostCard().removeSVar("AIPreferenceOverride");
|
||||
host.removeSVar("AIPreferenceOverride");
|
||||
}
|
||||
|
||||
if (aiLogic.equals("BeforeCombat")) {
|
||||
@@ -90,7 +92,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
} else if (aiLogic.equals("PriorityOptionalCost")) {
|
||||
boolean highPriority = false;
|
||||
// if we have more than one of these in hand, might not be worth waiting for optional cost payment on the additional copy
|
||||
highPriority |= CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.nameEquals(sa.getHostCard().getName())).size() > 1;
|
||||
highPriority |= CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.nameEquals(host.getName())).size() > 1;
|
||||
// if we are in danger in combat, no need to wait to pay the optional cost
|
||||
highPriority |= ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)
|
||||
&& ai.getGame().getCombat() != null && ComputerUtilCombat.lifeInDanger(ai, ai.getGame().getCombat());
|
||||
@@ -125,6 +127,40 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
return true;
|
||||
} else if (aiLogic.equals("Pongify")) {
|
||||
return SpecialAiLogic.doPongifyLogic(ai, sa);
|
||||
} else if (aiLogic.equals("Ashiok")) {
|
||||
final int loyalty = host.getCurrentLoyalty() - 1;
|
||||
CardCollectionView choices = new CardCollection();
|
||||
for (int i = loyalty; i >= 0; i--) {
|
||||
sa.setXManaCostPaid(i);
|
||||
choices = ai.getGame().getCardsIn(ZoneType.listValueOf(sa.getParam("Origin")));
|
||||
choices = CardLists.getValidCards(choices, sa.getParam("ChangeType"), host.getController(), host, sa);
|
||||
if (!choices.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if (aiLogic.equals("BestCard")) {
|
||||
CardCollectionView choices = ai.getGame().getCardsIn(ZoneType.listValueOf(sa.getParam("Origin")));
|
||||
choices = CardLists.getValidCards(choices, sa.getParam("ChangeType"), host.getController(), host, sa);
|
||||
if (!choices.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
} else if (aiLogic.startsWith("DiscardAllAndRetExiled")) {
|
||||
int numExiledWithSrc = CardLists.filter(ai.getCardsIn(ZoneType.Exile), CardPredicates.isExiledWith(host)).size();
|
||||
int curHandSize = ai.getCardsIn(ZoneType.Hand).size();
|
||||
|
||||
// minimum card advantage unless the hand will be fully reloaded
|
||||
int minAdv = aiLogic.contains(".minAdv") ? Integer.parseInt(aiLogic.substring(aiLogic.indexOf(".minAdv") + 7)) : 0;
|
||||
|
||||
if (numExiledWithSrc > curHandSize) {
|
||||
if (ComputerUtil.predictThreatenedObjects(ai, sa, true).contains(host)) {
|
||||
// Try to gain some card advantage if the card will die anyway
|
||||
// TODO: ideally, should evaluate the hand value and not discard good hands to it
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return (curHandSize + minAdv - 1 < numExiledWithSrc) || (numExiledWithSrc >= ai.getMaxHandSize());
|
||||
}
|
||||
|
||||
return super.checkAiLogic(ai, sa, aiLogic);
|
||||
@@ -161,8 +197,15 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
return SpecialCardAi.MazesEnd.consider(aiPlayer, sa);
|
||||
} else if (aiLogic.equals("Pongify")) {
|
||||
return sa.isTargetNumberValid(); // Pre-targeted in checkAiLogic
|
||||
} else if (aiLogic.equals("Ashiok")) {
|
||||
return true; // If checkAiLogic returns true, then we should be good to go
|
||||
} else if (aiLogic.equals("BestCard")) {
|
||||
return true; // If checkAiLogic returns true, then we should be good to go
|
||||
} else if (aiLogic.startsWith("DiscardAllAndRetExiled")) {
|
||||
return true; // If checkAiLogic returns true, then we should be good to go
|
||||
}
|
||||
}
|
||||
|
||||
if (isHidden(sa)) {
|
||||
return hiddenOriginCanPlayAI(aiPlayer, sa);
|
||||
}
|
||||
|
||||
@@ -245,25 +245,8 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
|
||||
&& !ComputerUtil.isPlayingReanimator(ai);
|
||||
}
|
||||
} else if (origin.equals(ZoneType.Exile)) {
|
||||
String logic = sa.getParam("AILogic");
|
||||
|
||||
if (logic != null && logic.startsWith("DiscardAllAndRetExiled")) {
|
||||
int numExiledWithSrc = CardLists.filter(ai.getCardsIn(ZoneType.Exile), CardPredicates.isExiledWith(source)).size();
|
||||
int curHandSize = ai.getCardsIn(ZoneType.Hand).size();
|
||||
|
||||
// minimum card advantage unless the hand will be fully reloaded
|
||||
int minAdv = logic.contains(".minAdv") ? Integer.parseInt(logic.substring(logic.indexOf(".minAdv") + 7)) : 0;
|
||||
|
||||
if (numExiledWithSrc > curHandSize) {
|
||||
if (ComputerUtil.predictThreatenedObjects(ai, sa, true).contains(source)) {
|
||||
// Try to gain some card advantage if the card will die anyway
|
||||
// TODO: ideally, should evaluate the hand value and not discard good hands to it
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return (curHandSize + minAdv - 1 < numExiledWithSrc) || (numExiledWithSrc >= ai.getMaxHandSize());
|
||||
}
|
||||
// TODO: nothing to do here at the moment
|
||||
return false;
|
||||
} else if (origin.equals(ZoneType.Stack)) {
|
||||
// time stop can do something like this:
|
||||
// Origin$ Stack | Destination$ Exile | SubAbility$ DBSkip
|
||||
|
||||
@@ -20,7 +20,6 @@ import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.card.CardPredicates;
|
||||
import forge.game.card.CardPredicates.Presets;
|
||||
import forge.game.card.CounterEnumType;
|
||||
import forge.game.combat.Combat;
|
||||
import forge.game.keyword.Keyword;
|
||||
import forge.game.phase.PhaseType;
|
||||
@@ -97,18 +96,6 @@ public class ChooseCardAi extends SpellAbilityAi {
|
||||
return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > ref;
|
||||
}
|
||||
});
|
||||
return !choices.isEmpty();
|
||||
} else if (aiLogic.equals("Ashiok")) {
|
||||
final int loyalty = host.getCounters(CounterEnumType.LOYALTY) - 1;
|
||||
for (int i = loyalty; i >= 0; i--) {
|
||||
sa.setXManaCostPaid(i);
|
||||
choices = ai.getGame().getCardsIn(choiceZone);
|
||||
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), host.getController(), host, sa);
|
||||
if (!choices.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return !choices.isEmpty();
|
||||
} else if (aiLogic.equals("RandomNonLand")) {
|
||||
return !CardLists.getValidCards(choices, "Card.nonLand", host.getController(), host, sa).isEmpty();
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
|
||||
import forge.ai.ComputerUtilAbility;
|
||||
import forge.ai.ComputerUtilCard;
|
||||
import forge.ai.ComputerUtilCost;
|
||||
@@ -31,6 +32,7 @@ import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.AbilitySub;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.staticability.StaticAbilityCantBeCast;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.collect.FCollection;
|
||||
@@ -228,11 +230,10 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
|
||||
return allow;
|
||||
}
|
||||
|
||||
//if Iona does prevent from casting, allow it to draw
|
||||
for (final Card io : player.getCardsIn(ZoneType.Battlefield, "Iona, Shield of Emeria")) {
|
||||
if (CardUtil.getColors(imprinted).hasAnyColor(MagicColor.fromName(io.getChosenColor()))) {
|
||||
return allow;
|
||||
}
|
||||
SpellAbility firstSpell = imprinted.getFirstSpellAbility();
|
||||
// check if something would prevent it from casting
|
||||
if (firstSpell == null || StaticAbilityCantBeCast.cantBeCastAbility(firstSpell, imprinted, owner)) {
|
||||
return allow;
|
||||
}
|
||||
|
||||
if (dmg == 0) {
|
||||
|
||||
@@ -55,15 +55,15 @@ public class GameCopier {
|
||||
public GameCopier(Game origGame) {
|
||||
this.origGame = origGame;
|
||||
}
|
||||
|
||||
|
||||
public Game getOriginalGame() {
|
||||
return origGame;
|
||||
}
|
||||
|
||||
|
||||
public Game getCopiedGame() {
|
||||
return gameObjectMap.getGame();
|
||||
}
|
||||
|
||||
|
||||
public Game makeCopy() {
|
||||
return makeCopy(null);
|
||||
}
|
||||
@@ -101,7 +101,7 @@ public class GameCopier {
|
||||
for (Player p : newGame.getPlayers()) {
|
||||
((PlayerZoneBattlefield) p.getZone(ZoneType.Battlefield)).setTriggers(false);
|
||||
}
|
||||
|
||||
|
||||
copyGameState(newGame);
|
||||
|
||||
for (Player p : newGame.getPlayers()) {
|
||||
@@ -124,7 +124,6 @@ public class GameCopier {
|
||||
System.err.println(c + " Remembered: " + o + "/" + o.getClass());
|
||||
c.addRemembered(o);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
for (SpellAbility sa : c.getSpellAbilities()) {
|
||||
@@ -153,7 +152,7 @@ public class GameCopier {
|
||||
if (advanceToPhase != null) {
|
||||
newGame.getPhaseHandler().devAdvanceToPhase(advanceToPhase);
|
||||
}
|
||||
|
||||
|
||||
return newGame;
|
||||
}
|
||||
|
||||
@@ -180,7 +179,7 @@ public class GameCopier {
|
||||
}
|
||||
newGame.getStack().add(newSa);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private RegisteredPlayer clonePlayer(RegisteredPlayer p) {
|
||||
@@ -227,7 +226,7 @@ public class GameCopier {
|
||||
// TODO: Verify that the above relationships are preserved bi-directionally or not.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final boolean USE_FROM_PAPER_CARD = true;
|
||||
private Card createCardCopy(Game newGame, Player newOwner, Card c) {
|
||||
if (c.isToken() && !c.isEmblem()) {
|
||||
@@ -277,7 +276,7 @@ public class GameCopier {
|
||||
// TODO: Controllers' list with timestamps should be copied.
|
||||
zoneOwner = playerMap.get(c.getController());
|
||||
newCard.setController(zoneOwner, 0);
|
||||
|
||||
|
||||
int setPower = c.getSetPower();
|
||||
int setToughness = c.getSetToughness();
|
||||
if (setPower != Integer.MAX_VALUE || setToughness != Integer.MAX_VALUE) {
|
||||
@@ -286,7 +285,7 @@ public class GameCopier {
|
||||
}
|
||||
newCard.setPTBoost(c.getPTBoostTable());
|
||||
newCard.setDamage(c.getDamage());
|
||||
|
||||
|
||||
newCard.setChangedCardTypes(c.getChangedCardTypesMap());
|
||||
newCard.setChangedCardKeywords(c.getChangedCardKeywords());
|
||||
newCard.setChangedCardNames(c.getChangedCardNames());
|
||||
@@ -335,15 +334,16 @@ public class GameCopier {
|
||||
if (c.getChosenPlayer() != null) {
|
||||
newCard.setChosenPlayer(playerMap.get(c.getChosenPlayer()));
|
||||
}
|
||||
if (!c.getChosenType().isEmpty()) {
|
||||
newCard.setChosenType(c.getChosenType());
|
||||
|
||||
SpellAbility first = c.getFirstSpellAbility();
|
||||
|
||||
if (first != null && first.hasChosenColor()) {
|
||||
newCard.setChosenColors(Lists.newArrayList(first.getChosenColors()), newCard.getFirstSpellAbility());
|
||||
}
|
||||
if (!c.getChosenType2().isEmpty()) {
|
||||
newCard.setChosenType2(c.getChosenType2());
|
||||
}
|
||||
if (c.getChosenColors() != null) {
|
||||
newCard.setChosenColors(Lists.newArrayList(c.getChosenColors()));
|
||||
if (first != null && first.hasChosenType()) {
|
||||
newCard.setChosenColors(Lists.newArrayList(first.getChosenType()), newCard.getFirstSpellAbility());
|
||||
}
|
||||
|
||||
if (!c.getNamedCard().isEmpty()) {
|
||||
newCard.setNamedCard(c.getNamedCard());
|
||||
}
|
||||
@@ -359,7 +359,7 @@ public class GameCopier {
|
||||
zoneOwner.getZone(zone).add(newCard);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static SpellAbility findSAInCard(SpellAbility sa, Card c) {
|
||||
String saDesc = sa.getDescription();
|
||||
for (SpellAbility cardSa : c.getAllSpellAbilities()) {
|
||||
@@ -387,7 +387,7 @@ public class GameCopier {
|
||||
return find(o);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public GameObject find(GameObject o) {
|
||||
GameObject result = cardMap.get(o);
|
||||
if (result != null)
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -22,8 +23,10 @@ import forge.game.card.CardView;
|
||||
import forge.game.card.IHasCardView;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Expressions;
|
||||
import forge.util.collect.FCollection;
|
||||
|
||||
/**
|
||||
* Base class for Triggers,ReplacementEffects and StaticAbilities.
|
||||
@@ -34,6 +37,7 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
|
||||
/** The host card. */
|
||||
protected Card hostCard;
|
||||
protected CardState cardState = null;
|
||||
private StaticAbility grantorStatic = null;
|
||||
|
||||
/** The map params. */
|
||||
protected Map<String, String> originalMapParams = Maps.newHashMap(),
|
||||
@@ -487,7 +491,7 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
|
||||
protected IHasSVars getSVarFallback() {
|
||||
if (getCardState() != null)
|
||||
return getCardState();
|
||||
return getHostCard();
|
||||
return getOriginalOrHost();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -501,7 +505,7 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
|
||||
|
||||
@Override
|
||||
public boolean hasSVar(final String name) {
|
||||
return sVars.containsKey(name) || getSVarFallback().hasSVar(name);
|
||||
return sVars.containsKey(name) || getOriginalOrHost().hasSVar(name);
|
||||
}
|
||||
|
||||
public Integer getSVarInt(final String name) {
|
||||
@@ -564,6 +568,19 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
|
||||
return !getHostCard().equals(getCardState().getCard());
|
||||
}
|
||||
|
||||
public Card getOriginalOrHost() {
|
||||
return ObjectUtils.defaultIfNull(getOriginalHost(), getHostCard());
|
||||
}
|
||||
|
||||
|
||||
public StaticAbility getGrantorStatic() {
|
||||
return grantorStatic;
|
||||
}
|
||||
|
||||
public void setGrantorStatic(final StaticAbility st) {
|
||||
grantorStatic = st;
|
||||
}
|
||||
|
||||
public Map<String, String> getChangedTextColors() {
|
||||
return _combineChangedMap(intrinsicChangedTextColors, changedTextColors);
|
||||
}
|
||||
@@ -621,4 +638,44 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
|
||||
// dont use setHostCard to not trigger the not copied parts yet
|
||||
copy.hostCard = host;
|
||||
}
|
||||
|
||||
|
||||
public String getChosenColor() {
|
||||
return getHostCard().getChosenColor(this);
|
||||
}
|
||||
public final Iterable<String> getChosenColors() {
|
||||
return getHostCard().getChosenColors(this);
|
||||
}
|
||||
|
||||
public final boolean hasChosenColor() {
|
||||
return getHostCard().hasChosenColor(this);
|
||||
}
|
||||
|
||||
public final boolean hasChosenColor(String s) {
|
||||
return getHostCard().hasChosenColor(s, this);
|
||||
}
|
||||
|
||||
public FCollection<Card> getExiledWith() {
|
||||
return getHostCard().getExiledWith(this);
|
||||
}
|
||||
|
||||
public boolean isExiledWith(Card object) {
|
||||
return getHostCard().isExiledWith(object, this);
|
||||
}
|
||||
|
||||
public final Iterable<String> getChosenType() {
|
||||
return getHostCard().getChosenType(this);
|
||||
}
|
||||
|
||||
public final String getChosenType(int index) {
|
||||
return getHostCard().getChosenType(this, index);
|
||||
}
|
||||
|
||||
public final boolean hasChosenType() {
|
||||
return getHostCard().hasChosenType(this);
|
||||
}
|
||||
|
||||
public void setChosenType(final Iterable<String> types) {
|
||||
getHostCard().setChosenType(types, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,13 +54,13 @@ public class ForgeScript {
|
||||
} else if (property.startsWith("ChosenColor")) {
|
||||
if (property.endsWith("Source") && isColorlessSource)
|
||||
return false;
|
||||
return source.hasChosenColor() && colors.hasAnyColor(MagicColor.fromName(source.getChosenColor()));
|
||||
return spellAbility.hasChosenColor() && colors.hasAnyColor(MagicColor.fromName(spellAbility.getChosenColor()));
|
||||
|
||||
} else if (property.startsWith("AnyChosenColor")) {
|
||||
if (property.endsWith("Source") && isColorlessSource)
|
||||
return false;
|
||||
return source.hasChosenColor()
|
||||
&& colors.hasAnyColor(ColorSet.fromNames(source.getChosenColors()).getColor());
|
||||
return spellAbility.hasChosenColor()
|
||||
&& colors.hasAnyColor(ColorSet.fromNames(spellAbility.getChosenColors()).getColor());
|
||||
|
||||
} else if (property.startsWith("non")) {
|
||||
// ... Other Card types
|
||||
@@ -71,13 +71,15 @@ public class ForgeScript {
|
||||
final String svar = property.substring(8);
|
||||
return cardState.hasSVar(svar);
|
||||
} else if (property.equals("ChosenType")) {
|
||||
return cardState.getTypeWithChanges().hasStringType(source.getChosenType());
|
||||
if (!spellAbility.hasChosenType()) {
|
||||
return false;
|
||||
}
|
||||
return cardState.getTypeWithChanges().hasStringType(spellAbility.getChosenType(0));
|
||||
} else if (property.equals("IsNotChosenType")) {
|
||||
return !cardState.getTypeWithChanges().hasStringType(source.getChosenType());
|
||||
} else if (property.equals("ChosenType2")) {
|
||||
return cardState.getTypeWithChanges().hasStringType(source.getChosenType2());
|
||||
} else if (property.equals("IsNotChosenType2")) {
|
||||
return !cardState.getTypeWithChanges().hasStringType(source.getChosenType2());
|
||||
if (spellAbility.hasChosenType() && cardState.getTypeWithChanges().hasStringType(spellAbility.getChosenType(0))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if (property.startsWith("HasSubtype")) {
|
||||
final String subType = property.substring(11);
|
||||
return cardState.getTypeWithChanges().hasSubtype(subType);
|
||||
|
||||
@@ -783,6 +783,10 @@ public class Game {
|
||||
cc.removeEncodedCard(c);
|
||||
cc.removeRemembered(c);
|
||||
}
|
||||
Card exile = c.getExiledWith();
|
||||
if (exile != null) {
|
||||
exile.removeExiledWith(c);
|
||||
}
|
||||
c.ceaseToExist();
|
||||
} else {
|
||||
// return stolen permanents
|
||||
|
||||
@@ -419,6 +419,7 @@ public class GameAction {
|
||||
Card with = c.getExiledWith();
|
||||
if (with != null) {
|
||||
with.removeUntilLeavesBattlefield(c);
|
||||
with.removeExiledWith(c);
|
||||
}
|
||||
|
||||
c.setExiledWith(null);
|
||||
|
||||
@@ -19,7 +19,7 @@ public class AbilityApiBased extends AbilityActivated {
|
||||
effect = api.getSpellEffect();
|
||||
|
||||
if (api.equals(ApiType.Mana) || api.equals(ApiType.ManaReflected)) {
|
||||
this.setManaPart(new AbilityManaPart(sourceCard, mapParams));
|
||||
this.setManaPart(new AbilityManaPart(sourceCard, this, mapParams));
|
||||
this.setUndoable(true); // will try at least
|
||||
}
|
||||
|
||||
|
||||
@@ -125,6 +125,10 @@ public class AbilityUtils {
|
||||
c = AbilityUtils.findEffectRoot(hostCard);
|
||||
}
|
||||
}
|
||||
else if (defined.equals("ExiledWith")) {
|
||||
// should not be needed to check timestamp there
|
||||
Iterables.addAll(cards, hostCard.getExiledWith(sa));
|
||||
}
|
||||
else if (defined.equals("Equipped")) {
|
||||
c = hostCard.getEquipping();
|
||||
}
|
||||
@@ -580,6 +584,10 @@ public class AbilityUtils {
|
||||
return AbilityUtils.xCount(ability.getOriginalHost(), calcX[1], ability) * multiplier;
|
||||
}
|
||||
|
||||
if (calcX[0].equals("ExiledWith")) {
|
||||
return CardFactoryUtil.handlePaid(card.getExiledWith(ability), calcX[1], card) * multiplier;
|
||||
}
|
||||
|
||||
if (calcX[0].startsWith("Remembered")) {
|
||||
// Add whole Remembered list to handlePaid
|
||||
final CardCollection list = new CardCollection();
|
||||
@@ -1050,6 +1058,9 @@ public class AbilityUtils {
|
||||
players.add(s.getActivatingPlayer());
|
||||
}
|
||||
}
|
||||
else if (defined.startsWith("ExiledWith")) {
|
||||
addPlayer(Lists.newArrayList(card.getExiledWith(sa)), defined, players);
|
||||
}
|
||||
else if (defined.startsWith("Remembered")) {
|
||||
addPlayer(card.getRemembered(), defined, players);
|
||||
}
|
||||
@@ -1725,7 +1736,7 @@ public class AbilityUtils {
|
||||
if (sq[0].contains("HasNumChosenColors")) {
|
||||
int sum = 0;
|
||||
for (Card card : AbilityUtils.getDefinedCards(sa.getHostCard(), sq[1], sa)) {
|
||||
sum += CardUtil.getColors(card).getSharedColors(ColorSet.fromNames(c.getChosenColors())).countColors();
|
||||
sum += CardUtil.getColors(card).getSharedColors(ColorSet.fromNames(sa.getChosenColors())).countColors();
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
@@ -1834,6 +1845,33 @@ public class AbilityUtils {
|
||||
|
||||
return CardFactoryUtil.doXMath(game.getCounterAddedThisTurn(cType, parts[2], parts[3], c, player, ctb), expr, c);
|
||||
}
|
||||
|
||||
if (l[0].startsWith("ExiledWith")) {
|
||||
return CardFactoryUtil.doXMath(c.getExiledWith(ctb).size(), expr, c);
|
||||
}
|
||||
|
||||
// Count$DevotionDual.<color name>.<color name>
|
||||
// Count$Devotion.<color name>
|
||||
if (sq[0].contains("Devotion")) {
|
||||
int colorOcurrencices = 0;
|
||||
String colorName = sq[1];
|
||||
if (colorName.contains("Chosen")) {
|
||||
colorName = MagicColor.toShortString(ctb.getChosenColor());
|
||||
}
|
||||
byte colorCode = ManaAtom.fromName(colorName);
|
||||
if (sq[0].equals("DevotionDual")) {
|
||||
colorCode |= ManaAtom.fromName(sq[2]);
|
||||
}
|
||||
for (Card c0 : player.getCardsIn(ZoneType.Battlefield)) {
|
||||
for (ManaCostShard sh : c0.getManaCost()) {
|
||||
if ((sh.getColorMask() & colorCode) != 0) {
|
||||
colorOcurrencices++;
|
||||
}
|
||||
}
|
||||
colorOcurrencices += c0.getAmountOfKeyword("Your devotion to each color and each combination of colors is increased by one.");
|
||||
}
|
||||
return CardFactoryUtil.doXMath(colorOcurrencices, expr, c);
|
||||
}
|
||||
}
|
||||
return CardFactoryUtil.xCount(c, s2);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public class SpellApiBased extends Spell {
|
||||
this.setIntrinsic(true);
|
||||
|
||||
if (api.equals(ApiType.Mana) || api.equals(ApiType.ManaReflected)) {
|
||||
this.setManaPart(new AbilityManaPart(sourceCard, mapParams));
|
||||
this.setManaPart(new AbilityManaPart(sourceCard, this, mapParams));
|
||||
}
|
||||
|
||||
if (api.equals(ApiType.ChangeZone) || api.equals(ApiType.ChangeZoneAll)) {
|
||||
|
||||
@@ -58,7 +58,7 @@ public class AnimateAllEffect extends AnimateEffectBase {
|
||||
// allow ChosenType - overrides anything else specified
|
||||
if (types.hasSubtype("ChosenType")) {
|
||||
types.clear();
|
||||
types.add(host.getChosenType());
|
||||
types.addAll(sa.getChosenType());
|
||||
}
|
||||
|
||||
final List<String> keywords = new ArrayList<>();
|
||||
@@ -89,7 +89,7 @@ public class AnimateAllEffect extends AnimateEffectBase {
|
||||
if (sa.hasParam("Colors")) {
|
||||
final String colors = sa.getParam("Colors");
|
||||
if (colors.equals("ChosenColor")) {
|
||||
tmpDesc = CardUtil.getShortColorsString(host.getChosenColors());
|
||||
tmpDesc = CardUtil.getShortColorsString(sa.getChosenColors());
|
||||
} else {
|
||||
tmpDesc = CardUtil.getShortColorsString(new ArrayList<>(Arrays.asList(colors.split(","))));
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ public class AnimateEffect extends AnimateEffectBase {
|
||||
// allow ChosenType - overrides anything else specified
|
||||
if (types.hasSubtype("ChosenType")) {
|
||||
types.clear();
|
||||
types.add(source.getChosenType());
|
||||
types.addAll(sa.getChosenType());
|
||||
}
|
||||
|
||||
final List<String> keywords = Lists.newArrayList();
|
||||
@@ -100,7 +100,7 @@ public class AnimateEffect extends AnimateEffectBase {
|
||||
final String colors = sa.getParam("Colors");
|
||||
if (colors.equals("ChosenColor")) {
|
||||
|
||||
tmpDesc = CardUtil.getShortColorsString(source.getChosenColors());
|
||||
tmpDesc = CardUtil.getShortColorsString(sa.getChosenColors());
|
||||
} else {
|
||||
tmpDesc = CardUtil.getShortColorsString(Arrays.asList(colors.split(",")));
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package forge.game.ability.effects;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.GameCommand;
|
||||
@@ -72,7 +73,7 @@ public class ChangeTextEffect extends SpellAbilityEffect {
|
||||
validTypes.addAll(CardType.Constant.CREATURE_TYPES);
|
||||
kindOfType = "creature";
|
||||
}
|
||||
changedTypeWordOriginal = sa.getActivatingPlayer().getController().chooseSomeType(kindOfType, sa, validTypes, Lists.newArrayList());
|
||||
changedTypeWordOriginal = Iterables.getFirst(sa.getActivatingPlayer().getController().chooseSomeType(kindOfType, sa, 1, 1, validTypes), changedTypeWordsArray[1]);
|
||||
} else {
|
||||
changedTypeWordOriginal = changedTypeWordsArray[0];
|
||||
}
|
||||
@@ -88,7 +89,8 @@ public class ChangeTextEffect extends SpellAbilityEffect {
|
||||
validTypes.addAll(CardType.Constant.CREATURE_TYPES);
|
||||
kindOfType = "creature";
|
||||
}
|
||||
changedTypeWordNew = sa.getActivatingPlayer().getController().chooseSomeType(kindOfType, sa, validTypes, forbiddenTypes);
|
||||
validTypes.removeAll(forbiddenTypes);
|
||||
changedTypeWordNew = Iterables.getFirst(sa.getActivatingPlayer().getController().chooseSomeType(kindOfType, sa, 1, 1, validTypes), changedTypeWordsArray[1]);
|
||||
} else {
|
||||
changedTypeWordNew = changedTypeWordsArray[1];
|
||||
}
|
||||
|
||||
@@ -193,12 +193,9 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect {
|
||||
} else {
|
||||
movedCard = game.getAction().moveTo(destination, c, libraryPos, sa, moveParams);
|
||||
if (destination == ZoneType.Exile && !c.isToken()) {
|
||||
Card host = sa.getOriginalHost();
|
||||
if (host == null) {
|
||||
host = sa.getHostCard();
|
||||
}
|
||||
movedCard.setExiledWith(host);
|
||||
movedCard.setExiledBy(host.getController());
|
||||
c.setExiledWith(source);
|
||||
source.addExiledWith(c, sa);
|
||||
c.setExiledBy(sa.getActivatingPlayer());
|
||||
}
|
||||
if (sa.hasParam("ExileFaceDown")) {
|
||||
movedCard.turnFaceDown(true);
|
||||
@@ -250,11 +247,13 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect {
|
||||
movedCard.setTimestamp(ts);
|
||||
}
|
||||
|
||||
|
||||
if (!movedCard.getZone().equals(originZone)) {
|
||||
Card meld = null;
|
||||
triggerList.put(originZone.getZoneType(), movedCard.getZone().getZoneType(), movedCard);
|
||||
|
||||
if (c.getMeldedWith() != null) {
|
||||
Card meld = game.getCardState(c.getMeldedWith(), null);
|
||||
meld = game.getCardState(c.getMeldedWith(), null);
|
||||
if (meld != null) {
|
||||
triggerList.put(originZone.getZoneType(), movedCard.getZone().getZoneType(), meld);
|
||||
}
|
||||
|
||||
@@ -685,16 +685,6 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
}
|
||||
movedCard.setTimestamp(ts);
|
||||
} else {
|
||||
// might set before card is moved only for nontoken
|
||||
Card host = null;
|
||||
if (destination.equals(ZoneType.Exile) && !gameCard.isToken()) {
|
||||
host = sa.getOriginalHost();
|
||||
if (host == null) {
|
||||
host = sa.getHostCard();
|
||||
}
|
||||
gameCard.setExiledWith(host);
|
||||
gameCard.setExiledBy(host.getController());
|
||||
}
|
||||
movedCard = game.getAction().moveTo(destination, gameCard, cause);
|
||||
if (ZoneType.Hand.equals(destination) && ZoneType.Command.equals(originZone.getZoneType())) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@@ -713,10 +703,9 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
|
||||
// might set after card is moved again if something has changed
|
||||
if (destination.equals(ZoneType.Exile) && !movedCard.isToken()) {
|
||||
movedCard.setExiledWith(host);
|
||||
if (host != null) {
|
||||
movedCard.setExiledBy(host.getController());
|
||||
}
|
||||
movedCard.setExiledWith(hostCard);
|
||||
hostCard.addExiledWith(movedCard, sa);
|
||||
movedCard.setExiledBy(sa.getActivatingPlayer());
|
||||
}
|
||||
|
||||
if (sa.hasParam("WithCountersType")) {
|
||||
@@ -728,6 +717,9 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
if (sa.hasParam("ExileFaceDown") || sa.hasParam("FaceDown")) {
|
||||
movedCard.turnFaceDown(true);
|
||||
}
|
||||
if (sa.hasParam("ExilePeek")) {
|
||||
movedCard.addMayLookTemp(player);
|
||||
}
|
||||
if (sa.hasParam("Foretold")) {
|
||||
movedCard.setForetold(true);
|
||||
movedCard.setForetoldThisTurn(true);
|
||||
@@ -810,7 +802,6 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
triggerList.triggerChangesZoneAll(game);
|
||||
counterTable.triggerCountersPutAll(game);
|
||||
|
||||
|
||||
if (sa.hasParam("AtEOT") && !triggerList.isEmpty()) {
|
||||
registerDelayedTrigger(sa, sa.getParam("AtEOT"), triggerList.allCards());
|
||||
}
|
||||
@@ -1307,12 +1298,9 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
else if (destination.equals(ZoneType.Exile)) {
|
||||
movedCard = game.getAction().exile(c, sa, moveParams);
|
||||
if (!c.isToken()) {
|
||||
Card host = sa.getOriginalHost();
|
||||
if (host == null) {
|
||||
host = sa.getHostCard();
|
||||
}
|
||||
movedCard.setExiledWith(host);
|
||||
movedCard.setExiledBy(host.getController());
|
||||
movedCard.setExiledWith(source);
|
||||
source.addExiledWith(movedCard, sa);
|
||||
movedCard.setExiledBy(sa.getActivatingPlayer());
|
||||
}
|
||||
if (sa.hasParam("ExileFaceDown")) {
|
||||
movedCard.turnFaceDown(true);
|
||||
@@ -1459,13 +1447,12 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
} else if (srcSA.getParam("Destination").equals("Graveyard")) {
|
||||
movedCard = game.getAction().moveToGraveyard(tgtHost, srcSA, params);
|
||||
} else if (srcSA.getParam("Destination").equals("Exile")) {
|
||||
Card host = srcSA.getOriginalHost();
|
||||
if (host == null) {
|
||||
host = srcSA.getHostCard();
|
||||
}
|
||||
Card hostCard = srcSA.getHostCard();
|
||||
movedCard = game.getAction().exile(tgtHost, srcSA, params);
|
||||
movedCard.setExiledWith(host);
|
||||
movedCard.setExiledBy(host.getController());
|
||||
|
||||
movedCard.setExiledWith(hostCard);
|
||||
hostCard.addExiledWith(movedCard, srcSA);
|
||||
movedCard.setExiledBy(srcSA.getActivatingPlayer());
|
||||
} else if (srcSA.getParam("Destination").equals("TopOfLibrary")) {
|
||||
movedCard = game.getAction().moveToLibrary(tgtHost, srcSA, params);
|
||||
} else if (srcSA.getParam("Destination").equals("Hand")) {
|
||||
@@ -1502,4 +1489,5 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public class ChooseColorEffect extends SpellAbilityEffect {
|
||||
if (chosenColors.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
card.setChosenColors(chosenColors);
|
||||
card.setChosenColors(chosenColors, sa);
|
||||
p.getGame().getAction().notifyOfValue(sa, card, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), Lang.joinHomogenous(chosenColors)), p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import forge.card.CardType;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
public class ChooseTypeEffect extends SpellAbilityEffect {
|
||||
|
||||
@@ -30,14 +31,12 @@ public class ChooseTypeEffect extends SpellAbilityEffect {
|
||||
public void resolve(SpellAbility sa) {
|
||||
final Card card = sa.getHostCard();
|
||||
final String type = sa.getParam("Type");
|
||||
final List<String> invalidTypes = sa.hasParam("InvalidTypes") ? Arrays.asList(sa.getParam("InvalidTypes").split(",")) : new ArrayList<>();
|
||||
int amount = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("Amount", "1"), sa);
|
||||
|
||||
final List<String> validTypes = new ArrayList<>();
|
||||
final List<String> validTypes = Lists.newArrayList();
|
||||
if (sa.hasParam("ValidTypes")) {
|
||||
validTypes.addAll(Arrays.asList(sa.getParam("ValidTypes").split(",")));
|
||||
}
|
||||
|
||||
if (validTypes.isEmpty()) {
|
||||
} else {
|
||||
switch (type) {
|
||||
case "Card":
|
||||
validTypes.addAll(CardType.getAllCardTypes());
|
||||
@@ -54,22 +53,22 @@ public class ChooseTypeEffect extends SpellAbilityEffect {
|
||||
}
|
||||
}
|
||||
|
||||
for (final String s : invalidTypes) {
|
||||
validTypes.remove(s);
|
||||
if (sa.hasParam("InvalidTypes")) {
|
||||
for (final String s : sa.getParam("InvalidTypes").split(",")) {
|
||||
validTypes.remove(s);
|
||||
}
|
||||
}
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
|
||||
if (!validTypes.isEmpty()) {
|
||||
for (final Player p : tgtPlayers) {
|
||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
||||
String choice = p.getController().chooseSomeType(type, sa, validTypes, invalidTypes);
|
||||
if (!sa.hasParam("Secondary")) {
|
||||
card.setChosenType(choice);
|
||||
} else {
|
||||
card.setChosenType2(choice);
|
||||
for (final Player p : getTargetPlayers(sa)) {
|
||||
if (!sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||
List<String> choices = Lists.newArrayList();
|
||||
for (int i = 0; i < amount; i++) {
|
||||
// the only one with multiple amount currently cares about the order
|
||||
choices.addAll(p.getController().chooseSomeType(type, sa, 1, 1, validTypes));
|
||||
validTypes.removeAll(choices);
|
||||
}
|
||||
card.setChosenType(choices, sa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,11 +49,10 @@ public class CleanUpEffect extends SpellAbilityEffect {
|
||||
source.setChosenPlayer(null);
|
||||
}
|
||||
if (sa.hasParam("ClearChosenType")) {
|
||||
source.setChosenType("");
|
||||
source.setChosenType2("");
|
||||
source.setChosenType(null, sa);;
|
||||
}
|
||||
if (sa.hasParam("ClearChosenColor")) {
|
||||
source.setChosenColors(null);
|
||||
source.setChosenColors(null, sa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardFactoryUtil;
|
||||
import forge.game.player.PlayerController.BinaryChoiceType;
|
||||
import forge.game.replacement.ReplacementResult;
|
||||
import forge.game.replacement.ReplacementType;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
@@ -158,7 +159,7 @@ public class CounterEffect extends SpellAbilityEffect {
|
||||
* <p>
|
||||
* removeFromStack.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param tgtSA
|
||||
* a {@link forge.game.spellability.SpellAbility} object.
|
||||
* @param srcSA
|
||||
@@ -170,7 +171,7 @@ public class CounterEffect extends SpellAbilityEffect {
|
||||
private static void removeFromStack(final SpellAbility tgtSA,
|
||||
final SpellAbility srcSA, final SpellAbilityStackInstance si) {
|
||||
final Game game = tgtSA.getActivatingPlayer().getGame();
|
||||
// Run any applicable replacement effects.
|
||||
// Run any applicable replacement effects.
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(tgtSA.getHostCard());
|
||||
repParams.put(AbilityKey.TgtSA, tgtSA);
|
||||
repParams.put(AbilityKey.Cause, srcSA.getHostCard());
|
||||
@@ -191,7 +192,10 @@ public class CounterEffect extends SpellAbilityEffect {
|
||||
String destination = srcSA.hasParam("Destination") ? srcSA.getParam("Destination") : tgtSA.isAftermath() ? "Exile" : "Graveyard";
|
||||
if (srcSA.hasParam("DestinationChoice")) {//Hinder
|
||||
List<String> pos = Arrays.asList(srcSA.getParam("DestinationChoice").split(","));
|
||||
destination = srcSA.getActivatingPlayer().getController().chooseSomeType(Localizer.getInstance().getMessage("lblRemoveDestination"), tgtSA, pos, null);
|
||||
|
||||
boolean value = srcSA.getActivatingPlayer().getController().chooseBinary(srcSA, Localizer.getInstance().getMessage("lblRemoveDestination"), BinaryChoiceType.BottomOfLibraryOrTopOfLibrary);
|
||||
|
||||
destination = pos.get(value ? 1 : 0);
|
||||
}
|
||||
if (tgtSA.isAbility()) {
|
||||
// For Ability-targeted counterspells - do not move it anywhere,
|
||||
@@ -229,7 +233,6 @@ public class CounterEffect extends SpellAbilityEffect {
|
||||
runParams.put(AbilityKey.Cause, srcSA.getHostCard());
|
||||
runParams.put(AbilityKey.CounteredSA, tgtSA);
|
||||
game.getTriggerHandler().runTrigger(TriggerType.Countered, runParams, false);
|
||||
|
||||
|
||||
if (!tgtSA.isAbility()) {
|
||||
game.getGameLog().add(GameLogEntryType.ZONE_CHANGE, "Send countered spell to " + destination);
|
||||
|
||||
@@ -31,6 +31,8 @@ import forge.util.Localizer;
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.collect.FCollectionView;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public class DigEffect extends SpellAbilityEffect {
|
||||
|
||||
@Override
|
||||
@@ -187,7 +189,7 @@ public class DigEffect extends SpellAbilityEffect {
|
||||
}
|
||||
else if (!changeValid.isEmpty()) {
|
||||
if (changeValid.contains("ChosenType")) {
|
||||
changeValid = changeValid.replace("ChosenType", host.getChosenType());
|
||||
changeValid = changeValid.replace("ChosenType", StringUtils.join(sa.getChosenType(),","));
|
||||
}
|
||||
valid = CardLists.getValidCards(top, changeValid.split(","), host.getController(), host, sa);
|
||||
}
|
||||
@@ -296,10 +298,6 @@ public class DigEffect extends SpellAbilityEffect {
|
||||
}
|
||||
Collections.reverse(movedCards);
|
||||
|
||||
Card effectHost = sa.getOriginalHost();
|
||||
if (effectHost == null) {
|
||||
effectHost = sa.getHostCard();
|
||||
}
|
||||
for (Card c : movedCards) {
|
||||
final ZoneType origin = c.getZone().getZoneType();
|
||||
final PlayerZone zone = c.getOwner().getZone(destZone1);
|
||||
@@ -324,8 +322,9 @@ public class DigEffect extends SpellAbilityEffect {
|
||||
c.addCounter(CounterType.getType(sa.getParam("ExileWithCounter")),
|
||||
1, player, true, counterTable);
|
||||
}
|
||||
c.setExiledWith(effectHost);
|
||||
c.setExiledBy(effectHost.getController());
|
||||
c.setExiledWith(host);
|
||||
host.addExiledWith(c, sa);
|
||||
c.setExiledBy(sa.getActivatingPlayer());
|
||||
}
|
||||
}
|
||||
if (!origin.equals(c.getZone().getZoneType())) {
|
||||
@@ -335,6 +334,11 @@ public class DigEffect extends SpellAbilityEffect {
|
||||
if (sa.hasParam("ExileFaceDown")) {
|
||||
c.turnFaceDown(true);
|
||||
}
|
||||
|
||||
if (sa.hasParam("ExilePeek")) {
|
||||
c.addMayLookTemp(player);
|
||||
}
|
||||
|
||||
if (sa.hasParam("Imprint")) {
|
||||
host.addImprintedCard(c);
|
||||
}
|
||||
@@ -393,8 +397,9 @@ public class DigEffect extends SpellAbilityEffect {
|
||||
c.addCounter(CounterType.getType(sa.getParam("ExileWithCounter")),
|
||||
1, player, true, counterTable);
|
||||
}
|
||||
c.setExiledWith(effectHost);
|
||||
c.setExiledBy(effectHost.getController());
|
||||
c.setExiledWith(host);
|
||||
host.addExiledWith(c, sa);
|
||||
c.setExiledBy(host.getController());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,8 +232,8 @@ public class EffectEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
// Set Chosen Color(s)
|
||||
if (hostCard.hasChosenColor()) {
|
||||
eff.setChosenColors(Lists.newArrayList(hostCard.getChosenColors()));
|
||||
if (sa.hasChosenColor()) {
|
||||
eff.setChosenColors(Lists.newArrayList(sa.getChosenColors()), sa);
|
||||
}
|
||||
|
||||
// Set Chosen Cards
|
||||
@@ -247,8 +247,8 @@ public class EffectEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
// Set Chosen Type
|
||||
if (!hostCard.getChosenType().isEmpty()) {
|
||||
eff.setChosenType(hostCard.getChosenType());
|
||||
if (sa.hasChosenType()) {
|
||||
eff.setChosenType(Lists.newArrayList(hostCard.getChosenType(sa)), sa);
|
||||
}
|
||||
|
||||
// Set Chosen name
|
||||
|
||||
@@ -56,12 +56,10 @@ public class MillEffect extends SpellAbilityEffect {
|
||||
p.getGame().getGameLog().add(GameLogEntryType.ZONE_CHANGE, sb.toString());
|
||||
}
|
||||
if (destination.equals(ZoneType.Exile)) {
|
||||
Card host = sa.getOriginalHost();
|
||||
if (host == null) {
|
||||
host = sa.getHostCard();
|
||||
}
|
||||
for (final Card c : milled) {
|
||||
c.setExiledWith(host);
|
||||
c.setExiledWith(source);
|
||||
source.addExiledWith(source, sa);
|
||||
c.setExiledBy(sa.getActivatingPlayer());
|
||||
if (facedown) {
|
||||
c.turnFaceDown(true);
|
||||
}
|
||||
|
||||
@@ -70,11 +70,11 @@ public class PlayEffect extends SpellAbilityEffect {
|
||||
amount = AbilityUtils.calculateAmount(source, sa.getParam("Amount"), sa);
|
||||
}
|
||||
|
||||
Player controller = activator;
|
||||
if (sa.hasParam("Controller")) {
|
||||
activator = AbilityUtils.getDefinedPlayers(source, sa.getParam("Controller"), sa).get(0);
|
||||
controller = AbilityUtils.getDefinedPlayers(source, sa.getParam("Controller"), sa).get(0);
|
||||
}
|
||||
|
||||
final Player controller = activator;
|
||||
CardCollection tgtCards;
|
||||
CardCollection showCards = new CardCollection();
|
||||
|
||||
@@ -118,7 +118,7 @@ public class PlayEffect extends SpellAbilityEffect {
|
||||
if (sa.hasParam("ChoiceNum")) {
|
||||
final int choicenum = AbilityUtils.calculateAmount(source, sa.getParam("ChoiceNum"), sa);
|
||||
tgtCards = new CardCollection(
|
||||
activator.getController().chooseCardsForEffect(choice, sa,
|
||||
controller.getController().chooseCardsForEffect(choice, sa,
|
||||
source + " - " + Localizer.getInstance().getMessage("lblChooseUpTo") + " " + Lang.nounWithNumeral(choicenum, "card"), 0, choicenum, true, null
|
||||
)
|
||||
);
|
||||
@@ -166,9 +166,9 @@ public class PlayEffect extends SpellAbilityEffect {
|
||||
|
||||
final CardCollection saidNoTo = new CardCollection();
|
||||
while (tgtCards.size() > saidNoTo.size() && saidNoTo.size() < amount && amount > 0) {
|
||||
activator.getController().tempShowCards(showCards);
|
||||
controller.getController().tempShowCards(showCards);
|
||||
Card tgtCard = controller.getController().chooseSingleEntityForEffect(tgtCards, sa, Localizer.getInstance().getMessage("lblSelectCardToPlay"), null);
|
||||
activator.getController().endTempShowCards();
|
||||
controller.getController().endTempShowCards();
|
||||
if (tgtCard == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public class ProtectAllEffect extends SpellAbilityEffect {
|
||||
game.getAction().notifyOfValue(sa, choser, Lang.joinHomogenous(gains), choser);
|
||||
} else {
|
||||
if (sa.getParam("Gains").equals("ChosenColor")) {
|
||||
for (final String color : host.getChosenColors()) {
|
||||
for (final String color : sa.getChosenColors()) {
|
||||
gains.add(color.toLowerCase());
|
||||
}
|
||||
} else if (sa.getParam("Gains").equals("TargetedCardColor")) {
|
||||
|
||||
@@ -97,7 +97,6 @@ public class ProtectEffect extends SpellAbilityEffect {
|
||||
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
final Card host = sa.getHostCard();
|
||||
final Game game = sa.getActivatingPlayer().getGame();
|
||||
|
||||
final boolean isChoice = sa.getParam("Gains").contains("Choice");
|
||||
@@ -117,7 +116,7 @@ public class ProtectEffect extends SpellAbilityEffect {
|
||||
game.getAction().notifyOfValue(sa, choser, Lang.joinHomogenous(gains), choser);
|
||||
} else {
|
||||
if (sa.getParam("Gains").equals("ChosenColor")) {
|
||||
for (final String color : host.getChosenColors()) {
|
||||
for (final String color : sa.getChosenColors()) {
|
||||
gains.add(color.toLowerCase());
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -3,6 +3,8 @@ package forge.game.ability.effects;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -289,7 +291,7 @@ public class PumpEffect extends SpellAbilityEffect {
|
||||
String defined = sa.getParam("DefinedKW");
|
||||
String replaced = "";
|
||||
if (defined.equals("ChosenType")) {
|
||||
replaced = host.getChosenType();
|
||||
replaced = ObjectUtils.defaultIfNull(sa.getChosenType(0), "");
|
||||
} else if (defined.equals("CardUIDSource")) {
|
||||
replaced = "CardUID_" + host.getId();
|
||||
} else if (defined.equals("ActivatorName")) {
|
||||
|
||||
@@ -62,8 +62,8 @@ public class ReplaceManaEffect extends SpellAbilityEffect {
|
||||
// replace color
|
||||
String color = sa.getParam("ReplaceColor");
|
||||
if ("Chosen".equals(color)) {
|
||||
if (card.hasChosenColor()) {
|
||||
color = MagicColor.toShortString(card.getChosenColor());
|
||||
if (sa.hasChosenColor()) {
|
||||
color = MagicColor.toShortString(sa.getChosenColor());
|
||||
}
|
||||
}
|
||||
if (sa.hasParam("ReplaceOnly")) {
|
||||
|
||||
@@ -81,7 +81,7 @@ public class SubgameEffect extends SpellAbilityEffect {
|
||||
List<String> chosenColors;
|
||||
SpellAbility cmdColorsa = new SpellAbility.EmptySa(ApiType.ChooseColor, cmd, player);
|
||||
chosenColors = player.getController().chooseColors(prompt,cmdColorsa, 1, 1, colorChoices);
|
||||
cmd.setChosenColors(chosenColors);
|
||||
cmd.setChosenColors(chosenColors, cmdColorsa);
|
||||
subgame.getAction().notifyOfValue(cmdColorsa, cmd, Localizer.getInstance().getMessage("lblPlayerPickedChosen", player.getName(), Lang.joinHomogenous(chosenColors)), player);
|
||||
}
|
||||
cmd.setCommander(true);
|
||||
|
||||
@@ -57,12 +57,12 @@ public class TokenEffect extends TokenEffectBase {
|
||||
|
||||
// linked Abilities, if it needs chosen values, but nothing is chosen, no token can be created
|
||||
if (sa.hasParam("TokenTypes")) {
|
||||
if (sa.getParam("TokenTypes").contains("ChosenType") && !host.hasChosenType()) {
|
||||
if (sa.getParam("TokenTypes").contains("ChosenType") && !sa.hasChosenType()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (sa.hasParam("TokenColors")) {
|
||||
if (sa.getParam("TokenColors").contains("ChosenColor") && !host.hasChosenColor()) {
|
||||
if (sa.getParam("TokenColors").contains("ChosenColor") && !sa.hasChosenColor()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package forge.game.card;
|
||||
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ForwardingTable;
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.Table;
|
||||
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
|
||||
public class ActivationTable extends ForwardingTable<SpellAbility, Optional<StaticAbility>, Integer> {
|
||||
Table<SpellAbility, Optional<StaticAbility>, Integer> dataTable = HashBasedTable.create();
|
||||
|
||||
@Override
|
||||
protected Table<SpellAbility, Optional<StaticAbility>, Integer> delegate() {
|
||||
return dataTable;
|
||||
}
|
||||
|
||||
protected SpellAbility getOriginal(SpellAbility sa) {
|
||||
SpellAbility original = null;
|
||||
SpellAbility root = sa.getRootAbility();
|
||||
|
||||
// because trigger spell abilities are copied, try to get original one
|
||||
if (root.isTrigger()) {
|
||||
original = root.getTrigger().getOverridingAbility();
|
||||
} else {
|
||||
original = ObjectUtils.defaultIfNull(root.getOriginalAbility(), sa);
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
public void add(SpellAbility sa) {
|
||||
SpellAbility root = sa.getRootAbility();
|
||||
SpellAbility original = getOriginal(sa);
|
||||
Optional<StaticAbility> st = Optional.fromNullable(root.getGrantorStatic());
|
||||
|
||||
delegate().put(original, st, ObjectUtils.defaultIfNull(get(original, st), 0) + 1);
|
||||
}
|
||||
|
||||
public Integer get(SpellAbility sa) {
|
||||
SpellAbility root = sa.getRootAbility();
|
||||
SpellAbility original = getOriginal(sa);
|
||||
Optional<StaticAbility> st = Optional.fromNullable(root.getGrantorStatic());
|
||||
|
||||
if (contains(original, st)) {
|
||||
return get(original, st);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.esotericsoftware.minlog.Log;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
@@ -294,9 +295,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
private NavigableMap<Long, Player> tempControllers = Maps.newTreeMap();
|
||||
|
||||
private String originalText = "", text = "";
|
||||
private String chosenType = "";
|
||||
private String chosenType2 = "";
|
||||
private List<String> chosenColors;
|
||||
private LinkedAbilityTable<String> chosenTypesTable = new LinkedAbilityTable<String>();
|
||||
private LinkedAbilityTable<String> chosenColorsTable = new LinkedAbilityTable<String>();
|
||||
private String chosenName = "";
|
||||
private String chosenName2 = "";
|
||||
private Integer chosenNumber;
|
||||
@@ -307,6 +307,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
|
||||
private Card exiledWith = null;
|
||||
private Player exiledBy = null;
|
||||
private ExileWithTable exiledWithTable = new ExileWithTable();
|
||||
|
||||
private Map<Long, Player> goad = Maps.newTreeMap();
|
||||
|
||||
@@ -338,17 +339,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
|
||||
private int planeswalkerAbilityActivated = 0;
|
||||
|
||||
private final Map<SpellAbility, Integer> numberTurnActivations = Maps.newHashMap();
|
||||
private final Map<SpellAbility, Integer> numberGameActivations = Maps.newHashMap();
|
||||
private final ActivationTable numberTurnActivations = new ActivationTable();
|
||||
private final ActivationTable numberGameActivations = new ActivationTable();
|
||||
|
||||
private final Table<SpellAbility, StaticAbility, Integer> numberTurnActivationsStatic = HashBasedTable.create();
|
||||
private final Table<SpellAbility, StaticAbility, Integer> numberGameActivationsStatic = HashBasedTable.create();
|
||||
|
||||
private final Map<SpellAbility, List<String>> chosenModesTurn = Maps.newHashMap();
|
||||
private final Map<SpellAbility, List<String>> chosenModesGame = Maps.newHashMap();
|
||||
|
||||
private final Table<SpellAbility, StaticAbility, List<String>> chosenModesTurnStatic = HashBasedTable.create();
|
||||
private final Table<SpellAbility, StaticAbility, List<String>> chosenModesGameStatic = HashBasedTable.create();
|
||||
private final ChosenModesTable chosenModesTurn = new ChosenModesTable();
|
||||
private final ChosenModesTable chosenModesGame = new ChosenModesTable();
|
||||
|
||||
// Enumeration for CMC request types
|
||||
public enum SplitCMCMode {
|
||||
@@ -1686,55 +1681,39 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
exiledBy = ep;
|
||||
}
|
||||
|
||||
// used for cards like Belbe's Portal, Conspiracy, Cover of Darkness, etc.
|
||||
public final String getChosenType() {
|
||||
return chosenType;
|
||||
public final Iterable<String> getChosenType(CardTraitBase ctb) {
|
||||
return chosenTypesTable.get(ctb);
|
||||
}
|
||||
|
||||
public final void setChosenType(final String s) {
|
||||
chosenType = s;
|
||||
view.updateChosenType(this);
|
||||
public final String getChosenType(CardTraitBase ctb, int index) {
|
||||
return Iterables.get(chosenTypesTable.get(ctb), index, null);
|
||||
}
|
||||
|
||||
public final boolean hasChosenType() {
|
||||
return chosenType != null && !chosenType.isEmpty();
|
||||
public final boolean hasChosenType(CardTraitBase ctb) {
|
||||
return !chosenTypesTable.get(ctb).isEmpty();
|
||||
}
|
||||
|
||||
// used by card Illusionary Terrain
|
||||
public final String getChosenType2() {
|
||||
return chosenType2;
|
||||
public void setChosenType(final Iterable<String> types, CardTraitBase ctb) {
|
||||
chosenTypesTable.set(types, ctb);
|
||||
}
|
||||
|
||||
public final void setChosenType2(final String s) {
|
||||
chosenType2 = s;
|
||||
view.updateChosenType2(this);
|
||||
public String getChosenColor(CardTraitBase ctb) {
|
||||
return Iterables.getFirst(chosenColorsTable.get(ctb), null);
|
||||
}
|
||||
public final Iterable<String> getChosenColors(CardTraitBase ctb) {
|
||||
return chosenColorsTable.get(ctb);
|
||||
}
|
||||
|
||||
public final boolean hasChosenType2() {
|
||||
return chosenType2 != null && !chosenType2.isEmpty();
|
||||
public final boolean hasChosenColor(CardTraitBase ctb) {
|
||||
return !chosenColorsTable.get(ctb).isEmpty();
|
||||
}
|
||||
|
||||
public final String getChosenColor() {
|
||||
if (hasChosenColor()) {
|
||||
return chosenColors.get(0);
|
||||
}
|
||||
return "";
|
||||
public final boolean hasChosenColor(String s, CardTraitBase ctb) {
|
||||
return chosenColorsTable.contains(s, ctb);
|
||||
}
|
||||
public final Iterable<String> getChosenColors() {
|
||||
if (chosenColors == null) {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
return chosenColors;
|
||||
}
|
||||
public final void setChosenColors(final List<String> s) {
|
||||
chosenColors = s;
|
||||
view.updateChosenColors(this);
|
||||
}
|
||||
public boolean hasChosenColor() {
|
||||
return chosenColors != null && !chosenColors.isEmpty();
|
||||
}
|
||||
public boolean hasChosenColor(String s) {
|
||||
return chosenColors != null && chosenColors.contains(s);
|
||||
|
||||
public void setChosenColors(final Iterable<String> colors, CardTraitBase ctb) {
|
||||
chosenColorsTable.set(colors, ctb);
|
||||
}
|
||||
|
||||
public final Card getChosenCard() {
|
||||
@@ -6858,20 +6837,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
}
|
||||
|
||||
public void addAbilityActivated(SpellAbility ability) {
|
||||
SpellAbility original = ability.getOriginalAbility();
|
||||
if (original == null) {
|
||||
original = ability;
|
||||
}
|
||||
|
||||
int turnActivated = getAbilityActivatedThisTurn(ability);
|
||||
int gameActivated = getAbilityActivatedThisGame(ability);
|
||||
if (ability.getGrantorStatic() != null) {
|
||||
numberTurnActivationsStatic.put(original, ability.getGrantorStatic(), turnActivated + 1);
|
||||
numberGameActivationsStatic.put(original, ability.getGrantorStatic(), gameActivated + 1);
|
||||
} else {
|
||||
numberTurnActivations.put(original, turnActivated + 1);
|
||||
numberGameActivations.put(original, gameActivated + 1);
|
||||
}
|
||||
numberTurnActivations.add(ability);
|
||||
numberGameActivations.add(ability);
|
||||
|
||||
if (ability.isPwAbility()) {
|
||||
addPlaneswalkerAbilityActivated();
|
||||
@@ -6879,121 +6846,27 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
}
|
||||
|
||||
public int getAbilityActivatedThisTurn(SpellAbility ability) {
|
||||
SpellAbility original = ability.getOriginalAbility();
|
||||
if (original == null) {
|
||||
original = ability;
|
||||
}
|
||||
|
||||
if (ability.getGrantorStatic() != null) {
|
||||
if (numberTurnActivationsStatic.contains(original, ability.getGrantorStatic())) {
|
||||
return numberTurnActivationsStatic.get(original, ability.getGrantorStatic());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return numberTurnActivations.containsKey(original) ? numberTurnActivations.get(original) : 0;
|
||||
return numberTurnActivations.get(ability);
|
||||
}
|
||||
|
||||
public int getAbilityActivatedThisGame(SpellAbility ability) {
|
||||
SpellAbility original = ability.getOriginalAbility();
|
||||
if (original == null) {
|
||||
original = ability;
|
||||
}
|
||||
|
||||
if (ability.getGrantorStatic() != null) {
|
||||
if (numberGameActivationsStatic.contains(original, ability.getGrantorStatic())) {
|
||||
return numberGameActivationsStatic.get(original, ability.getGrantorStatic());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return numberGameActivations.containsKey(original) ? numberGameActivations.get(original) : 0;
|
||||
return numberGameActivations.get(ability);
|
||||
}
|
||||
|
||||
public List<String> getChosenModesTurn(SpellAbility ability) {
|
||||
SpellAbility original = null;
|
||||
SpellAbility root = ability.getRootAbility();
|
||||
|
||||
// because trigger spell abilities are copied, try to get original one
|
||||
if (root.isTrigger()) {
|
||||
original = root.getTrigger().getOverridingAbility();
|
||||
} else {
|
||||
original = ability.getOriginalAbility();
|
||||
if (original == null) {
|
||||
original = ability;
|
||||
}
|
||||
}
|
||||
|
||||
if (ability.getGrantorStatic() != null) {
|
||||
return chosenModesTurnStatic.get(original, ability.getGrantorStatic());
|
||||
}
|
||||
return chosenModesTurn.get(original);
|
||||
return chosenModesTurn.get(ability);
|
||||
}
|
||||
public List<String> getChosenModesGame(SpellAbility ability) {
|
||||
SpellAbility original = null;
|
||||
SpellAbility root = ability.getRootAbility();
|
||||
|
||||
// because trigger spell abilities are copied, try to get original one
|
||||
if (root.isTrigger()) {
|
||||
original = root.getTrigger().getOverridingAbility();
|
||||
} else {
|
||||
original = ability.getOriginalAbility();
|
||||
if (original == null) {
|
||||
original = ability;
|
||||
}
|
||||
}
|
||||
|
||||
if (ability.getGrantorStatic() != null) {
|
||||
return chosenModesGameStatic.get(original, ability.getGrantorStatic());
|
||||
}
|
||||
return chosenModesGame.get(original);
|
||||
return chosenModesGame.get(ability);
|
||||
}
|
||||
|
||||
public void addChosenModes(SpellAbility ability, String mode) {
|
||||
SpellAbility original = null;
|
||||
SpellAbility root = ability.getRootAbility();
|
||||
|
||||
// because trigger spell abilities are copied, try to get original one
|
||||
if (root.isTrigger()) {
|
||||
original = root.getTrigger().getOverridingAbility();
|
||||
} else {
|
||||
original = ability.getOriginalAbility();
|
||||
if (original == null) {
|
||||
original = ability;
|
||||
}
|
||||
}
|
||||
|
||||
if (ability.getGrantorStatic() != null) {
|
||||
List<String> result = chosenModesTurnStatic.get(original, ability.getGrantorStatic());
|
||||
if (result == null) {
|
||||
result = Lists.newArrayList();
|
||||
chosenModesTurnStatic.put(original, ability.getGrantorStatic(), result);
|
||||
}
|
||||
result.add(mode);
|
||||
result = chosenModesGameStatic.get(original, ability.getGrantorStatic());
|
||||
if (result == null) {
|
||||
result = Lists.newArrayList();
|
||||
chosenModesGameStatic.put(original, ability.getGrantorStatic(), result);
|
||||
}
|
||||
result.add(mode);
|
||||
} else {
|
||||
List<String> result = chosenModesTurn.get(original);
|
||||
if (result == null) {
|
||||
result = Lists.newArrayList();
|
||||
chosenModesTurn.put(original, result);
|
||||
}
|
||||
result.add(mode);
|
||||
|
||||
result = chosenModesGame.get(original);
|
||||
if (result == null) {
|
||||
result = Lists.newArrayList();
|
||||
chosenModesGame.put(original, result);
|
||||
}
|
||||
result.add(mode);
|
||||
}
|
||||
chosenModesTurn.put(ability, mode);
|
||||
chosenModesGame.put(ability, mode);
|
||||
}
|
||||
|
||||
public void resetChosenModeTurn() {
|
||||
chosenModesTurn.clear();
|
||||
chosenModesTurnStatic.clear();
|
||||
}
|
||||
|
||||
public int getPlaneswalkerAbilityActivated() {
|
||||
@@ -7007,7 +6880,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
public void resetActivationsPerTurn() {
|
||||
planeswalkerAbilityActivated = 0;
|
||||
numberTurnActivations.clear();
|
||||
numberTurnActivationsStatic.clear();
|
||||
}
|
||||
|
||||
public void addCanBlockAdditional(int n, long timestamp) {
|
||||
@@ -7077,6 +6949,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
return edition.getBorderColor();
|
||||
}
|
||||
|
||||
|
||||
public final void addUntilLeavesBattlefield(final Card c) {
|
||||
untilLeavesBattlefield = view.addCard(untilLeavesBattlefield, c, TrackableProperty.UntilLeavesBattlefield);
|
||||
}
|
||||
@@ -7092,4 +6965,32 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
public final void clearUntilLeavesBattlefield() {
|
||||
untilLeavesBattlefield = view.clearCards(untilLeavesBattlefield, TrackableProperty.UntilLeavesBattlefield);
|
||||
}
|
||||
|
||||
public void addExiledWith(Card object) {
|
||||
this.exiledWithTable.put(object, this);
|
||||
}
|
||||
|
||||
public void addExiledWith(Card object, CardTraitBase ctb) {
|
||||
this.exiledWithTable.put(object, ctb);
|
||||
}
|
||||
|
||||
public boolean removeExiledWith(Card object) {
|
||||
return exiledWithTable.remove(object);
|
||||
}
|
||||
|
||||
public ExileWithTable getExiledWithTable() {
|
||||
return exiledWithTable;
|
||||
}
|
||||
|
||||
public void setExiledWithTable(Table<Card, Optional<StaticAbility>, FCollection<Card>> map) {
|
||||
exiledWithTable = new ExileWithTable(map);
|
||||
}
|
||||
|
||||
public FCollection<Card> getExiledWith(CardTraitBase ctb) {
|
||||
return exiledWithTable.get(ctb);
|
||||
}
|
||||
|
||||
public boolean isExiledWith(Card object, CardTraitBase ctb) {
|
||||
return exiledWithTable.contains(object, ctb);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +129,6 @@ public class CardFactory {
|
||||
* </p>
|
||||
* */
|
||||
private final static Card copySpellHost(final SpellAbility sourceSA, final SpellAbility targetSA, Player controller) {
|
||||
final Card source = sourceSA.getHostCard();
|
||||
final Card original = targetSA.getHostCard();
|
||||
final Card c = copyCard(original, true);
|
||||
|
||||
@@ -138,7 +137,7 @@ public class CardFactory {
|
||||
String tmp = "";
|
||||
final String newColor = sourceSA.getParam("CopyIsColor");
|
||||
if (newColor.equals("ChosenColor")) {
|
||||
tmp = CardUtil.getShortColorsString(source.getChosenColors());
|
||||
tmp = CardUtil.getShortColorsString(sourceSA.getChosenColors());
|
||||
} else {
|
||||
tmp = CardUtil.getShortColorsString(Lists.newArrayList(newColor.split(",")));
|
||||
}
|
||||
|
||||
@@ -1052,28 +1052,6 @@ public class CardFactoryUtil {
|
||||
}
|
||||
return doXMath(colorOcurrencices, m, c);
|
||||
}
|
||||
// Count$DevotionDual.<color name>.<color name>
|
||||
// Count$Devotion.<color name>
|
||||
if (sq[0].contains("Devotion")) {
|
||||
int colorOcurrencices = 0;
|
||||
String colorName = sq[1];
|
||||
if (colorName.contains("Chosen")) {
|
||||
colorName = MagicColor.toShortString(c.getChosenColor());
|
||||
}
|
||||
byte colorCode = ManaAtom.fromName(colorName);
|
||||
if (sq[0].equals("DevotionDual")) {
|
||||
colorCode |= ManaAtom.fromName(sq[2]);
|
||||
}
|
||||
for (Card c0 : cc.getCardsIn(ZoneType.Battlefield)) {
|
||||
for (ManaCostShard sh : c0.getManaCost()) {
|
||||
if ((sh.getColorMask() & colorCode) != 0) {
|
||||
colorOcurrencices++;
|
||||
}
|
||||
}
|
||||
colorOcurrencices += c0.getAmountOfKeyword("Your devotion to each color and each combination of colors is increased by one.");
|
||||
}
|
||||
return doXMath(colorOcurrencices, m, c);
|
||||
}
|
||||
|
||||
if (sq[0].contains("ColorsCtrl")) {
|
||||
final String restriction = l[0].substring(11);
|
||||
@@ -2751,8 +2729,8 @@ public class CardFactoryUtil {
|
||||
sb.append(", then put the rest on the bottom of your library.");
|
||||
final Trigger hideawayTrigger = TriggerHandler.parseTrigger(sb.toString(), card, intrinsic);
|
||||
|
||||
String hideawayDig = "DB$ Dig | Defined$ You | DigNum$ 4 | DestinationZone$ Exile | ExileFaceDown$ True | RememberChanged$ True";
|
||||
String hideawayEffect = "DB$ Effect | StaticAbilities$ STHideawayEffectLookAtCard | ForgetOnMoved$ Exile | RememberObjects$ Remembered | Duration$ Permanent";
|
||||
String hideawayDig = "DB$ Dig | Defined$ You | DigNum$ 4 | DestinationZone$ Exile | ExileFaceDown$ True";
|
||||
String hideawayEffect = "DB$ Effect | StaticAbilities$ STHideawayEffectLookAtCard | ForgetOnMoved$ Exile | RememberObjects$ ExiledWith | Duration$ Permanent";
|
||||
|
||||
String lookAtCard = "Mode$ Continuous | Affected$ Card.IsRemembered | MayLookAt$ True | EffectZone$ Command | AffectedZone$ Exile | Description$ You may look at the exiled card.";
|
||||
|
||||
@@ -2771,12 +2749,6 @@ public class CardFactoryUtil {
|
||||
gainControlTrigger.setOverridingAbility((AbilitySub)effectSA.copy());
|
||||
triggers.add(gainControlTrigger);
|
||||
|
||||
// when the card with hideaway leaves the battlefield, forget all exiled cards
|
||||
final Trigger changeZoneTrigger = TriggerHandler.parseTrigger("Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Battlefield | Destination$ Any | TriggerZone$ Battlefield | Static$ True", card, intrinsic);
|
||||
String cleanupStr = "DB$ Cleanup | ClearRemembered$ True";
|
||||
changeZoneTrigger.setOverridingAbility(AbilityFactory.getAbility(cleanupStr, card));
|
||||
triggers.add(changeZoneTrigger);
|
||||
|
||||
for (final Trigger trigger : triggers) {
|
||||
inst.addTrigger(trigger);
|
||||
}
|
||||
|
||||
@@ -378,23 +378,23 @@ public class CardProperty {
|
||||
return false;
|
||||
}
|
||||
|
||||
Card host = source;
|
||||
//Static Abilites doesn't have spellAbility or OriginalHost
|
||||
if (spellAbility != null) {
|
||||
host = spellAbility.getOriginalHost();
|
||||
if (host == null) {
|
||||
host = spellAbility.getHostCard();
|
||||
}
|
||||
|
||||
if (!source.isExiledWith(card, spellAbility)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!card.getExiledWith().equals(host)) {
|
||||
if (!card.getExiledWith().equals(source)) {
|
||||
return false;
|
||||
}
|
||||
} else if (property.equals("ExiledWithEffectSource")) {
|
||||
if (card.getExiledWith() == null) {
|
||||
return false;
|
||||
}
|
||||
if (!card.getExiledWith().equals(source.getEffectSource())) {
|
||||
if (!source.isEmblem() && !source.getType().hasSubtype("Effect")) {
|
||||
return false;
|
||||
}
|
||||
if (!source.getEffectSource().isExiledWith(card, spellAbility)) {
|
||||
return false;
|
||||
}
|
||||
} else if (property.equals("EncodedWithSource")) {
|
||||
@@ -895,23 +895,22 @@ public class CardProperty {
|
||||
return Iterables.any(game.getCardsIn(ZoneType.Battlefield), CardPredicates.sharesNameWith(card));
|
||||
} else if (restriction.equals("ThisTurnCast")) {
|
||||
return Iterables.any(CardUtil.getThisTurnCast("Card", source), CardPredicates.sharesNameWith(card));
|
||||
} else if (restriction.equals("MovedToGrave")) {
|
||||
for (final SpellAbility sa : source.getCurrentState().getNonManaAbilities()) {
|
||||
final SpellAbility root = sa.getRootAbility();
|
||||
if (root != null && (root.getPaidList("MovedToGrave") != null)
|
||||
&& !root.getPaidList("MovedToGrave").isEmpty()) {
|
||||
final CardCollectionView cards = root.getPaidList("MovedToGrave");
|
||||
for (final Card c : cards) {
|
||||
String name = c.getName();
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
name = c.getPaperCard().getName();
|
||||
}
|
||||
if (card.getName().equals(name)) {
|
||||
return true;
|
||||
}
|
||||
} else if (restriction.equals("MovedToGrave") && spellAbility instanceof SpellAbility) {
|
||||
final SpellAbility root = ((SpellAbility)spellAbility).getRootAbility();
|
||||
if (root != null && (root.getPaidList("MovedToGrave") != null)
|
||||
&& !root.getPaidList("MovedToGrave").isEmpty()) {
|
||||
final CardCollectionView cards = root.getPaidList("MovedToGrave");
|
||||
for (final Card c : cards) {
|
||||
String name = c.getName();
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
name = c.getPaperCard().getName();
|
||||
}
|
||||
if (card.getName().equals(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} else if (restriction.equals("NonToken")) {
|
||||
return !CardLists.filter(game.getCardsIn(ZoneType.Battlefield),
|
||||
@@ -966,7 +965,7 @@ public class CardProperty {
|
||||
final String restriction = property.split("sharesControllerWith ")[1];
|
||||
if (restriction.startsWith("Remembered") || restriction.startsWith("Imprinted")) {
|
||||
CardCollection list = AbilityUtils.getDefinedCards(source, restriction, spellAbility);
|
||||
return !CardLists.filter(list, CardPredicates.sharesControllerWith(card)).isEmpty();
|
||||
return Iterables.any(list, CardPredicates.sharesControllerWith(card));
|
||||
}
|
||||
}
|
||||
} else if (property.startsWith("sharesOwnerWith")) {
|
||||
|
||||
@@ -317,6 +317,9 @@ public final class CardUtil {
|
||||
newCopy.setCastFrom(in.getCastFrom());
|
||||
|
||||
newCopy.setExiledWith(getLKICopy(in.getExiledWith(), cachedMap));
|
||||
newCopy.setExiledBy(in.getExiledBy());
|
||||
|
||||
newCopy.setExiledWithTable(in.getExiledWithTable());
|
||||
|
||||
return newCopy;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package forge.game.card;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -319,20 +318,6 @@ public class CardView extends GameEntityView {
|
||||
set(TrackableProperty.ShieldCount, c.getShieldCount());
|
||||
}
|
||||
|
||||
public String getChosenType() {
|
||||
return get(TrackableProperty.ChosenType);
|
||||
}
|
||||
void updateChosenType(Card c) {
|
||||
set(TrackableProperty.ChosenType, c.getChosenType());
|
||||
}
|
||||
|
||||
public String getChosenType2() {
|
||||
return get(TrackableProperty.ChosenType2);
|
||||
}
|
||||
void updateChosenType2(Card c) {
|
||||
set(TrackableProperty.ChosenType2, c.getChosenType2());
|
||||
}
|
||||
|
||||
public String getChosenNumber() {
|
||||
return get(TrackableProperty.ChosenNumber);
|
||||
}
|
||||
@@ -340,13 +325,6 @@ public class CardView extends GameEntityView {
|
||||
set(TrackableProperty.ChosenNumber, c.getChosenNumber().toString());
|
||||
}
|
||||
|
||||
public List<String> getChosenColors() {
|
||||
return get(TrackableProperty.ChosenColors);
|
||||
}
|
||||
void updateChosenColors(Card c) {
|
||||
set(TrackableProperty.ChosenColors, c.getChosenColors());
|
||||
}
|
||||
|
||||
public FCollectionView<CardView> getMergedCardsCollection() {
|
||||
return get(TrackableProperty.MergedCardsCollection);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package forge.game.card;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ForwardingTable;
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Table;
|
||||
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
|
||||
public class ChosenModesTable extends ForwardingTable<SpellAbility, Optional<StaticAbility>, List<String>> {
|
||||
Table<SpellAbility, Optional<StaticAbility>, List<String>> dataTable = HashBasedTable.create();
|
||||
|
||||
@Override
|
||||
protected Table<SpellAbility, Optional<StaticAbility>, List<String>> delegate() {
|
||||
return dataTable;
|
||||
}
|
||||
|
||||
protected SpellAbility getOriginal(SpellAbility sa) {
|
||||
SpellAbility original = null;
|
||||
SpellAbility root = sa.getRootAbility();
|
||||
|
||||
// because trigger spell abilities are copied, try to get original one
|
||||
if (root.isTrigger()) {
|
||||
original = root.getTrigger().getOverridingAbility();
|
||||
} else {
|
||||
original = ObjectUtils.defaultIfNull(root.getOriginalAbility(), sa);
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
public List<String> put(SpellAbility sa, String mode) {
|
||||
SpellAbility root = sa.getRootAbility();
|
||||
SpellAbility original = getOriginal(sa);
|
||||
Optional<StaticAbility> st = Optional.fromNullable(root.getGrantorStatic());
|
||||
|
||||
List<String> old;
|
||||
if (contains(original, st)) {
|
||||
old = get(original, st);
|
||||
old.add(mode);
|
||||
} else {
|
||||
old = Lists.newArrayList(mode);
|
||||
delegate().put(original, st, old);
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
public List<String> get(SpellAbility sa) {
|
||||
SpellAbility root = sa.getRootAbility();
|
||||
SpellAbility original = getOriginal(sa);
|
||||
Optional<StaticAbility> st = Optional.fromNullable(root.getGrantorStatic());
|
||||
if (contains(original, st)) {
|
||||
return get(original, st);
|
||||
} else {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
}
|
||||
}
|
||||
18
forge-game/src/main/java/forge/game/card/ExileWithTable.java
Normal file
18
forge-game/src/main/java/forge/game/card/ExileWithTable.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package forge.game.card;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.Table;
|
||||
|
||||
import forge.game.staticability.StaticAbility;
|
||||
import forge.util.collect.FCollection;
|
||||
|
||||
public class ExileWithTable extends LinkedAbilityTable<Card> {
|
||||
|
||||
public ExileWithTable(Table<Card, Optional<StaticAbility>, FCollection<Card>> map) {
|
||||
this.putAll(map);
|
||||
}
|
||||
|
||||
|
||||
public ExileWithTable() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package forge.game.card;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ForwardingTable;
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Table;
|
||||
|
||||
import forge.game.CardTraitBase;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
import forge.util.collect.FCollection;
|
||||
|
||||
public class LinkedAbilityTable<T> extends ForwardingTable<Card, Optional<StaticAbility>, FCollection<T>> {
|
||||
private Table<Card, Optional<StaticAbility>, FCollection<T>> dataTable = HashBasedTable.create();
|
||||
|
||||
@Override
|
||||
protected Table<Card, Optional<StaticAbility>, FCollection<T>> delegate() {
|
||||
return dataTable;
|
||||
}
|
||||
|
||||
protected FCollection<T> getSupplier() {
|
||||
return new FCollection<T>();
|
||||
}
|
||||
|
||||
protected FCollection<T> putInternal(T object, Card host, StaticAbility stAb) {
|
||||
host = ObjectUtils.defaultIfNull(host.getEffectSource(), host);
|
||||
Optional<StaticAbility> st = Optional.fromNullable(stAb);
|
||||
FCollection<T> old;
|
||||
if (contains(host, st)) {
|
||||
old = get(host, st);
|
||||
} else {
|
||||
old = getSupplier();
|
||||
delegate().put(host, st, old);
|
||||
}
|
||||
old.add(object);
|
||||
return old;
|
||||
}
|
||||
|
||||
public FCollection<T> put(T object, Card host) {
|
||||
return putInternal(object, host, null);
|
||||
}
|
||||
|
||||
public FCollection<T> put(T object, CardTraitBase ctb) {
|
||||
return putInternal(object, ctb.getOriginalOrHost(), ctb.getGrantorStatic());
|
||||
}
|
||||
|
||||
protected void setInternal(Iterable<T> list, Card host, StaticAbility stAb) {
|
||||
host = ObjectUtils.defaultIfNull(host.getEffectSource(), host);
|
||||
Optional<StaticAbility> st = Optional.fromNullable(stAb);
|
||||
if (list == null || Iterables.isEmpty(list)) {
|
||||
delegate().remove(host, st);
|
||||
} else {
|
||||
FCollection<T> old = getSupplier();
|
||||
old.addAll(list);
|
||||
delegate().put(host, st, old);
|
||||
}
|
||||
}
|
||||
|
||||
public void set(Iterable<T> list, CardTraitBase ctb) {
|
||||
setInternal(list, ctb.getOriginalOrHost(), ctb.getGrantorStatic());
|
||||
}
|
||||
|
||||
public FCollection<T> get(CardTraitBase ctb) {
|
||||
Card host = ctb.getOriginalOrHost();
|
||||
host = ObjectUtils.defaultIfNull(host.getEffectSource(), host);
|
||||
Optional<StaticAbility> st = Optional.fromNullable(ctb.getGrantorStatic());
|
||||
if (contains(host, st)) {
|
||||
return get(host, st);
|
||||
} else {
|
||||
return FCollection.<T>getEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(T object, CardTraitBase ctb) {
|
||||
return get(ctb).contains(object);
|
||||
}
|
||||
|
||||
public boolean remove(T value) {
|
||||
boolean changed = false;
|
||||
for (FCollection<T> col : delegate().values()) {
|
||||
if (col.remove(value)) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package forge.game.card.token;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
@@ -332,7 +331,7 @@ public class TokenInfo {
|
||||
final Card host = sa.getHostCard();
|
||||
final Game game = host.getGame();
|
||||
|
||||
String edition = ObjectUtils.firstNonNull(sa.getOriginalHost(), host).getSetCode();
|
||||
String edition = sa.getOriginalOrHost().getSetCode();
|
||||
PaperToken token = StaticData.instance().getAllTokens().getToken(script, edition);
|
||||
|
||||
if (token == null) {
|
||||
@@ -359,14 +358,16 @@ public class TokenInfo {
|
||||
// need to be done after text change so it isn't affected by that
|
||||
if (sa.hasParam("TokenTypes")) {
|
||||
String types = sa.getParam("TokenTypes");
|
||||
types = types.replace("ChosenType", sa.getHostCard().getChosenType());
|
||||
if (sa.hasChosenType()) {
|
||||
types = types.replace("ChosenType", Iterables.getFirst(sa.getChosenType(), null));
|
||||
}
|
||||
result.addType(types);
|
||||
result.setName(types);
|
||||
}
|
||||
|
||||
if (sa.hasParam("TokenColors")) {
|
||||
String colors = sa.getParam("TokenColors");
|
||||
colors = colors.replace("ChosenColor", sa.getHostCard().getChosenColor());
|
||||
colors = colors.replace("ChosenColor", sa.getChosenColor());
|
||||
result.setColor(MagicColor.toShortString(colors));
|
||||
}
|
||||
|
||||
|
||||
@@ -233,7 +233,8 @@ public class CostAdjustment {
|
||||
sa.getHostCard().addDelved(c);
|
||||
final Card d = game.getAction().exile(c, null);
|
||||
d.setExiledWith(sa.getHostCard());
|
||||
d.setExiledBy(sa.getHostCard().getController());
|
||||
sa.getHostCard().addExiledWith(d, sa);
|
||||
d.setExiledBy(sa.getActivatingPlayer());
|
||||
table.put(ZoneType.Graveyard, d.getZone().getZoneType(), d);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public class CostChooseCreatureType extends CostPart {
|
||||
|
||||
@Override
|
||||
public boolean payAsDecided(Player payer, PaymentDecision pd, SpellAbility sa) {
|
||||
sa.getHostCard().setChosenType(pd.type);
|
||||
sa.getHostCard().setChosenType(pd.types, sa);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import forge.util.TextUtil;
|
||||
|
||||
public class PaymentDecision {
|
||||
public int c = 0;
|
||||
public String type;
|
||||
public Iterable<String> types = null;
|
||||
|
||||
public final CardCollection cards = new CardCollection();
|
||||
public final List<Mana> mana;
|
||||
@@ -43,9 +43,9 @@ public class PaymentDecision {
|
||||
cards.add(chosen);
|
||||
}
|
||||
|
||||
public PaymentDecision(String choice) {
|
||||
public PaymentDecision(Iterable<String> choices) {
|
||||
this(null, null, null, null, null);
|
||||
type = choice;
|
||||
types = choices;
|
||||
}
|
||||
|
||||
public static PaymentDecision card(Card chosen) {
|
||||
@@ -86,8 +86,8 @@ public class PaymentDecision {
|
||||
return TextUtil.concatWithSpace("Payment Decision:", TextUtil.addSuffix(String.valueOf(c),","), cards.toString());
|
||||
}
|
||||
|
||||
public static PaymentDecision type(String choice) {
|
||||
return new PaymentDecision(choice);
|
||||
public static PaymentDecision types(Iterable<String> choices) {
|
||||
return new PaymentDecision(choices);
|
||||
}
|
||||
|
||||
public static PaymentDecision players(List<Player> players) {
|
||||
|
||||
@@ -24,10 +24,9 @@ import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.card.CardType;
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.card.Card;
|
||||
@@ -138,10 +137,9 @@ public class Untap extends Phase {
|
||||
}
|
||||
if (kw.startsWith("OnlyUntapChosen") && !hasChosen) {
|
||||
List<String> validTypes = Arrays.asList(kw.split(":")[1].split(","));
|
||||
List<String> invalidTypes = Lists.newArrayList(CardType.getAllCardTypes());
|
||||
invalidTypes.removeAll(validTypes);
|
||||
final String chosen = player.getController().chooseSomeType("Card", new SpellAbility.EmptySa(ApiType.ChooseType, null, player), validTypes, invalidTypes);
|
||||
list = CardLists.getType(list,chosen);
|
||||
SpellAbility emptySA = new SpellAbility.EmptySa(ApiType.ChooseType, null, player);
|
||||
final String chosen = Iterables.getFirst(player.getController().chooseSomeType("Card", emptySA, 1, 1, validTypes), "");
|
||||
list = CardLists.getType(list, chosen);
|
||||
hasChosen = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3039,7 +3039,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
List<String> chosenColors;
|
||||
SpellAbility cmdColorsa = new SpellAbility.EmptySa(ApiType.ChooseColor, cmd, p);
|
||||
chosenColors = p.getController().chooseColors(prompt,cmdColorsa, 1, 1, colorChoices);
|
||||
cmd.setChosenColors(chosenColors);
|
||||
cmd.setChosenColors(chosenColors, cmdColorsa);
|
||||
p.getGame().getAction().notifyOfValue(cmdColorsa, cmd, Localizer.getInstance().getMessage("lblPlayerPickedChosen", p.getName(), Lang.joinHomogenous(chosenColors)), p);
|
||||
}
|
||||
cmd.setCommander(true);
|
||||
|
||||
@@ -48,9 +48,9 @@ import forge.item.PaperCard;
|
||||
import forge.util.ITriggerEvent;
|
||||
import forge.util.collect.FCollectionView;
|
||||
|
||||
/**
|
||||
/**
|
||||
* A prototype for player controller class
|
||||
*
|
||||
*
|
||||
* Handles phase skips for now.
|
||||
*/
|
||||
public abstract class PlayerController {
|
||||
@@ -72,6 +72,7 @@ public abstract class PlayerController {
|
||||
UntapTimeVault,
|
||||
LeftOrRight,
|
||||
AddOrRemove,
|
||||
BottomOfLibraryOrTopOfLibrary,
|
||||
}
|
||||
|
||||
protected final GameView gameView;
|
||||
@@ -113,16 +114,16 @@ public abstract class PlayerController {
|
||||
public abstract CardCollectionView choosePermanentsToSacrifice(SpellAbility sa, int min, int max, CardCollectionView validTargets, String message);
|
||||
public abstract CardCollectionView choosePermanentsToDestroy(SpellAbility sa, int min, int max, CardCollectionView validTargets, String message);
|
||||
public abstract TargetChoices chooseNewTargetsFor(SpellAbility ability, Predicate<GameObject> filter, boolean optional);
|
||||
public abstract boolean chooseTargetsFor(SpellAbility currentAbility); // this is bad a function for it assigns targets to sa inside its body
|
||||
public abstract boolean chooseTargetsFor(SpellAbility currentAbility); // this is bad a function for it assigns targets to sa inside its body
|
||||
|
||||
// Specify a target of a spell (Spellskite)
|
||||
public abstract Pair<SpellAbilityStackInstance, GameObject> chooseTarget(SpellAbility sa, List<Pair<SpellAbilityStackInstance, GameObject>> allTargets);
|
||||
|
||||
// Q: why is there min/max and optional at once? A: This is to handle cases like 'choose 3 to 5 cards or none at all'
|
||||
// Q: why is there min/max and optional at once? A: This is to handle cases like 'choose 3 to 5 cards or none at all'
|
||||
public abstract CardCollectionView chooseCardsForEffect(CardCollectionView sourceList, SpellAbility sa, String title, int min, int max, boolean isOptional, Map<String, Object> params);
|
||||
|
||||
|
||||
public final <T extends GameEntity> T chooseSingleEntityForEffect(FCollectionView<T> optionList, SpellAbility sa, String title, Map<String, Object> params) { return chooseSingleEntityForEffect(optionList, null, sa, title, false, null, params); }
|
||||
public final <T extends GameEntity> T chooseSingleEntityForEffect(FCollectionView<T> optionList, SpellAbility sa, String title, boolean isOptional, Map<String, Object> params) { return chooseSingleEntityForEffect(optionList, null, sa, title, isOptional, null, params); }
|
||||
public final <T extends GameEntity> T chooseSingleEntityForEffect(FCollectionView<T> optionList, SpellAbility sa, String title, boolean isOptional, Map<String, Object> params) { return chooseSingleEntityForEffect(optionList, null, sa, title, isOptional, null, params); }
|
||||
public abstract <T extends GameEntity> T chooseSingleEntityForEffect(FCollectionView<T> optionList, DelayedReveal delayedReveal, SpellAbility sa, String title, boolean isOptional, Player relatedPlayer, Map<String, Object> params);
|
||||
|
||||
public abstract List<SpellAbility> chooseSpellAbilitiesForEffect(List<SpellAbility> spells, SpellAbility sa, String title, int num, Map<String, Object> params);
|
||||
@@ -174,11 +175,6 @@ public abstract class PlayerController {
|
||||
public abstract List<SpellAbility> chooseSaToActivateFromOpeningHand(List<SpellAbility> usableFromOpeningHand);
|
||||
public abstract Mana chooseManaFromPool(List<Mana> manaChoices);
|
||||
|
||||
public abstract String chooseSomeType(String kindOfType, SpellAbility sa, Collection<String> validTypes, List<String> invalidTypes, boolean isOptional);
|
||||
public final String chooseSomeType(String kindOfType, SpellAbility sa, Collection<String> validTypes, List<String> invalidTypes) {
|
||||
return chooseSomeType(kindOfType, sa, validTypes, invalidTypes, false);
|
||||
}
|
||||
|
||||
public abstract Object vote(SpellAbility sa, String prompt, List<Object> options, ListMultimap<Object, Player> votes, Player forPlayer);
|
||||
public abstract boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, String question);
|
||||
|
||||
@@ -208,7 +204,7 @@ public abstract class PlayerController {
|
||||
public final boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice) { return chooseBinary(sa, question, kindOfChoice, (Boolean) null); }
|
||||
public abstract boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice, Boolean defaultChioce);
|
||||
public boolean chooseBinary(SpellAbility sa, String question, BinaryChoiceType kindOfChoice, Map<String, Object> params) { return chooseBinary(sa, question, kindOfChoice); }
|
||||
|
||||
|
||||
public abstract boolean chooseFlipResult(SpellAbility sa, Player flipper, boolean[] results, boolean call);
|
||||
public abstract Card chooseProtectionShield(GameEntity entityBeingDamaged, List<String> options, Map<String, Card> choiceMap);
|
||||
|
||||
@@ -220,6 +216,8 @@ public abstract class PlayerController {
|
||||
public abstract ICardFace chooseSingleCardFace(SpellAbility sa, String message, Predicate<ICardFace> cpp, String name);
|
||||
public abstract List<String> chooseColors(String message, SpellAbility sa, int min, int max, List<String> options);
|
||||
|
||||
public abstract List<String> chooseSomeType(String kindOfType, SpellAbility sa, int min, int max, List<String> validTypes);
|
||||
|
||||
public abstract CounterType chooseCounterType(List<CounterType> options, SpellAbility sa, String prompt,
|
||||
Map<String, Object> params);
|
||||
|
||||
@@ -259,7 +257,7 @@ public abstract class PlayerController {
|
||||
public abstract String chooseCardName(SpellAbility sa, Predicate<ICardFace> cpp, String valid, String message);
|
||||
|
||||
public abstract String chooseCardName(SpellAbility sa, List<ICardFace> faces, String message);
|
||||
// better to have this odd method than those if playerType comparison in ChangeZone
|
||||
// better to have this odd method than those if playerType comparison in ChangeZone
|
||||
public abstract Card chooseSingleCardForZoneChange(ZoneType destination, List<ZoneType> origin, SpellAbility sa, CardCollection fetchList, DelayedReveal delayedReveal, String selectPrompt, boolean isOptional, Player decider);
|
||||
|
||||
public abstract List<Card> chooseCardsForZoneChange(ZoneType destination, List<ZoneType> origin, SpellAbility sa, CardCollection fetchList, int min, int max, DelayedReveal delayedReveal, String selectPrompt, Player decider);
|
||||
|
||||
@@ -71,6 +71,7 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
private transient List<Mana> lastManaProduced = Lists.newArrayList();
|
||||
|
||||
private transient Card sourceCard;
|
||||
private transient SpellAbility spellAbility;
|
||||
|
||||
|
||||
// Spells paid with this mana spell can't be countered.
|
||||
@@ -84,8 +85,9 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
* @param sourceCard
|
||||
* a {@link forge.game.card.Card} object.
|
||||
*/
|
||||
public AbilityManaPart(final Card sourceCard, final Map<String, String> params) {
|
||||
public AbilityManaPart(final Card sourceCard, final SpellAbility sa, final Map<String, String> params) {
|
||||
this.sourceCard = sourceCard;
|
||||
this.spellAbility = sa;
|
||||
|
||||
origProduced = params.containsKey("Produced") ? params.get("Produced") : "1";
|
||||
this.manaRestrictions = params.containsKey("RestrictValid") ? params.get("RestrictValid") : "";
|
||||
@@ -413,9 +415,11 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
* @return a {@link java.lang.String} object.
|
||||
*/
|
||||
public final String mana() {
|
||||
if (this.getOrigProduced().contains("Chosen")) {
|
||||
if (this.getSourceCard() != null && this.getSourceCard().hasChosenColor()) {
|
||||
return MagicColor.toShortString(this.getSourceCard().getChosenColor());
|
||||
if (getOrigProduced().contains("Chosen")) {
|
||||
if (spellAbility == null) {
|
||||
return "";
|
||||
} else {
|
||||
return MagicColor.toShortString(spellAbility.getChosenColor());
|
||||
}
|
||||
}
|
||||
return this.getOrigProduced();
|
||||
@@ -499,15 +503,15 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
* a {@link java.lang.String} object.
|
||||
* @return a boolean.
|
||||
*/
|
||||
public final boolean canProduce(final String s, final SpellAbility sa) {
|
||||
public final boolean canProduce(final String s) {
|
||||
// Any mana never means Colorless?
|
||||
if (isAnyMana() && !s.equals("C")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String origProduced = getOrigProduced();
|
||||
if (origProduced.contains("Chosen") && sourceCard != null ) {
|
||||
if (getSourceCard().hasChosenColor() && MagicColor.toShortString(getSourceCard().getChosenColor()).contains(s)) {
|
||||
if (origProduced.contains("Chosen") && spellAbility != null ) {
|
||||
if (spellAbility.hasChosenColor() && MagicColor.toShortString(spellAbility.getChosenColor()).contains(s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ public final class AbilitySub extends SpellAbility implements java.io.Serializab
|
||||
effect = api.getSpellEffect();
|
||||
|
||||
if (api.equals(ApiType.Mana) || api.equals(ApiType.ManaReflected)) {
|
||||
this.setManaPart(new AbilityManaPart(ca, mapParams));
|
||||
this.setManaPart(new AbilityManaPart(ca, this, mapParams));
|
||||
}
|
||||
|
||||
if (api.equals(ApiType.ChangeZone) || api.equals(ApiType.ChangeZoneAll)) {
|
||||
|
||||
@@ -110,7 +110,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
private Player targetingPlayer = null;
|
||||
|
||||
private SpellAbility grantorOriginal = null;
|
||||
private StaticAbility grantorStatic = null;
|
||||
|
||||
private CardCollection splicedCards = null;
|
||||
|
||||
@@ -253,7 +252,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
|
||||
public boolean canThisProduce(final String s) {
|
||||
AbilityManaPart mp = getManaPart();
|
||||
if (mp != null && metConditions() && mp.canProduce(s, this)) {
|
||||
if (mp != null && metConditions() && mp.canProduce(s)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -994,7 +993,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
|
||||
clone.setPayCosts(getPayCosts().copy());
|
||||
if (manaPart != null) {
|
||||
clone.manaPart = new AbilityManaPart(host, mapParams);
|
||||
clone.manaPart = new AbilityManaPart(host, clone, mapParams);
|
||||
}
|
||||
|
||||
// need to copy the damage tables
|
||||
@@ -2203,14 +2202,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
grantorOriginal = sa;
|
||||
}
|
||||
|
||||
public StaticAbility getGrantorStatic() {
|
||||
return grantorStatic;
|
||||
}
|
||||
|
||||
public void setGrantorStatic(final StaticAbility st) {
|
||||
grantorStatic = st;
|
||||
}
|
||||
|
||||
public boolean isAlternativeCost(AlternativeCost ac) {
|
||||
if (ac.equals(altCost)) {
|
||||
return true;
|
||||
|
||||
@@ -339,7 +339,7 @@ public class SpellAbilityCondition extends SpellAbilityVariables {
|
||||
}
|
||||
|
||||
if (this.getColorToCheck() != null) {
|
||||
if (!sa.getHostCard().hasChosenColor(this.getColorToCheck())) {
|
||||
if (!sa.hasChosenColor(this.getColorToCheck())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,7 +362,7 @@ public class SpellAbilityRestriction extends SpellAbilityVariables {
|
||||
}
|
||||
|
||||
if (getColorToCheck() != null) {
|
||||
if (!sa.getHostCard().hasChosenColor(getColorToCheck())) {
|
||||
if (!sa.hasChosenColor(getColorToCheck())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ public final class StaticAbilityContinuous {
|
||||
|
||||
if (layer == StaticAbilityLayer.TEXT && params.containsKey("GainTextOf")) {
|
||||
final String valid = params.get("GainTextOf");
|
||||
CardCollection allValid = CardLists.getValidCards(game.getCardsInGame(), valid, hostCard.getController(), hostCard, null);
|
||||
CardCollection allValid = CardLists.getValidCards(game.getCardsInGame(), valid, hostCard.getController(), hostCard, stAb);
|
||||
if (allValid.size() > 1) {
|
||||
// TODO: if ever necessary, support gaining text of multiple cards at the same time
|
||||
System.err.println("Error: GainTextOf parameter was not defined as a unique card for " + hostCard);
|
||||
@@ -215,10 +215,10 @@ public final class StaticAbilityContinuous {
|
||||
Iterables.removeIf(addKeywords, new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
if (!hostCard.hasChosenColor() && input.contains("ChosenColor")) {
|
||||
if (!stAb.hasChosenColor() && input.contains("ChosenColor")) {
|
||||
return true;
|
||||
}
|
||||
if (!hostCard.hasChosenType() && input.contains("ChosenType")) {
|
||||
if (!stAb.hasChosenType() && input.contains("ChosenType")) {
|
||||
return true;
|
||||
}
|
||||
if (!hostCard.hasChosenNumber() && input.contains("ChosenNumber")) {
|
||||
@@ -271,7 +271,7 @@ public final class StaticAbilityContinuous {
|
||||
String keywordDefined = params.get("KeywordDefined");
|
||||
CardCollectionView definedCards = game.getCardsIn(ZoneType.Battlefield);
|
||||
definedCards = CardLists.getValidCards(definedCards, keywordDefined, hostCard.getController(),
|
||||
hostCard, null);
|
||||
hostCard, stAb);
|
||||
for (Card c : definedCards) {
|
||||
final int cmc = c.getCMC();
|
||||
String y = (input.replace(" from EachCMCAmongDefined", ":Card.cmcEQ"
|
||||
@@ -294,12 +294,12 @@ public final class StaticAbilityContinuous {
|
||||
|
||||
@Override
|
||||
public String apply(String input) {
|
||||
if (hostCard.hasChosenColor()) {
|
||||
input = input.replaceAll("ChosenColor", StringUtils.capitalize(hostCard.getChosenColor()));
|
||||
input = input.replaceAll("chosenColor", hostCard.getChosenColor().toLowerCase());
|
||||
if (stAb.hasChosenColor()) {
|
||||
input = input.replaceAll("ChosenColor", StringUtils.capitalize(stAb.getChosenColor()));
|
||||
input = input.replaceAll("chosenColor", stAb.getChosenColor().toLowerCase());
|
||||
}
|
||||
if (hostCard.hasChosenType()) {
|
||||
input = input.replaceAll("ChosenType", hostCard.getChosenType());
|
||||
if (stAb.hasChosenType()) {
|
||||
input = input.replaceAll("ChosenType", stAb.getChosenType(0));
|
||||
}
|
||||
if (hostCard.hasChosenNumber()) {
|
||||
input = input.replaceAll("ChosenNumber", String.valueOf(hostCard.getChosenNumber()));
|
||||
@@ -377,10 +377,10 @@ public final class StaticAbilityContinuous {
|
||||
Iterables.removeIf(addTypes, new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
if (input.equals("ChosenType") && !hostCard.hasChosenType()) {
|
||||
if (input.equals("ChosenType") && !stAb.hasChosenType()) {
|
||||
return true;
|
||||
}
|
||||
if (input.equals("ChosenType2") && !hostCard.hasChosenType2()) {
|
||||
if (input.equals("ChosenType2") && stAb.getChosenType(1) == null) {
|
||||
return true;
|
||||
}
|
||||
if (input.equals("ImprintedCreatureType")) {
|
||||
@@ -401,11 +401,11 @@ public final class StaticAbilityContinuous {
|
||||
addTypes = Lists.transform(addTypes, new Function<String, String>() {
|
||||
@Override
|
||||
public String apply(String input) {
|
||||
if (hostCard.hasChosenType2()) {
|
||||
input = input.replaceAll("ChosenType2", hostCard.getChosenType2());
|
||||
if (stAb.getChosenType(1) != null) {
|
||||
input = input.replaceAll("ChosenType2", stAb.getChosenType(1));
|
||||
}
|
||||
if (hostCard.hasChosenType()) {
|
||||
input = input.replaceAll("ChosenType", hostCard.getChosenType());
|
||||
if (stAb.getChosenType(0) != null) {
|
||||
input = input.replaceAll("ChosenType", stAb.getChosenType(0));
|
||||
}
|
||||
return input;
|
||||
}
|
||||
@@ -419,7 +419,7 @@ public final class StaticAbilityContinuous {
|
||||
Iterables.removeIf(removeTypes, new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
if (input.equals("ChosenType") && !hostCard.hasChosenType()) {
|
||||
if (input.equals("ChosenType") && !stAb.hasChosenType()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -458,7 +458,7 @@ public final class StaticAbilityContinuous {
|
||||
if (params.containsKey("AddColor")) {
|
||||
final String colors = params.get("AddColor");
|
||||
if (colors.equals("ChosenColor")) {
|
||||
addColors = CardUtil.getShortColorsString(hostCard.getChosenColors());
|
||||
addColors = CardUtil.getShortColorsString(stAb.getChosenColors());
|
||||
} else if (colors.equals("All")) {
|
||||
addColors = "W U B R G";
|
||||
} else {
|
||||
@@ -469,7 +469,7 @@ public final class StaticAbilityContinuous {
|
||||
if (params.containsKey("SetColor")) {
|
||||
final String colors = params.get("SetColor");
|
||||
if (colors.equals("ChosenColor")) {
|
||||
addColors = CardUtil.getShortColorsString(hostCard.getChosenColors());
|
||||
addColors = CardUtil.getShortColorsString(stAb.getChosenColors());
|
||||
} else if (colors.equals("All")) {
|
||||
addColors = "W U B R G";
|
||||
} else {
|
||||
@@ -504,7 +504,7 @@ public final class StaticAbilityContinuous {
|
||||
if ("True".equals(look)) {
|
||||
look = "You";
|
||||
}
|
||||
mayLookAt = AbilityUtils.getDefinedPlayers(hostCard, look, null);
|
||||
mayLookAt = AbilityUtils.getDefinedPlayers(hostCard, look, stAb);
|
||||
}
|
||||
if (params.containsKey("MayPlay")) {
|
||||
controllerMayPlay = true;
|
||||
@@ -567,7 +567,7 @@ public final class StaticAbilityContinuous {
|
||||
}
|
||||
}
|
||||
if (params.containsKey("ControlOpponentsSearchingLibrary")) {
|
||||
Player cntl = Iterables.getFirst(AbilityUtils.getDefinedPlayers(hostCard, params.get("ControlOpponentsSearchingLibrary"), null), null);
|
||||
Player cntl = Iterables.getFirst(AbilityUtils.getDefinedPlayers(hostCard, params.get("ControlOpponentsSearchingLibrary"), stAb), null);
|
||||
p.addControlledWhileSearching(se.getTimestamp(), cntl);
|
||||
}
|
||||
|
||||
@@ -619,8 +619,8 @@ public final class StaticAbilityContinuous {
|
||||
if (changeColorWordsTo != null) {
|
||||
final byte color;
|
||||
if (changeColorWordsTo.equals("ChosenColor")) {
|
||||
if (hostCard.hasChosenColor()) {
|
||||
color = MagicColor.fromName(Iterables.getFirst(hostCard.getChosenColors(), null));
|
||||
if (stAb.hasChosenColor()) {
|
||||
color = MagicColor.fromName(stAb.getChosenColor());
|
||||
} else {
|
||||
color = 0;
|
||||
}
|
||||
@@ -766,7 +766,7 @@ public final class StaticAbilityContinuous {
|
||||
}
|
||||
|
||||
CardCollectionView cardsIGainedAbilitiesFrom = game.getCardsIn(validZones);
|
||||
cardsIGainedAbilitiesFrom = CardLists.getValidCards(cardsIGainedAbilitiesFrom, valids, hostCard.getController(), hostCard, null);
|
||||
cardsIGainedAbilitiesFrom = CardLists.getValidCards(cardsIGainedAbilitiesFrom, valids, hostCard.getController(), hostCard, stAb);
|
||||
|
||||
for (Card c : cardsIGainedAbilitiesFrom) {
|
||||
for (SpellAbility sa : c.getSpellAbilities()) {
|
||||
@@ -936,7 +936,7 @@ public final class StaticAbilityContinuous {
|
||||
final String[] strngs = params.get("Affected").split(",");
|
||||
|
||||
for (Player p : controller.getGame().getPlayersInTurnOrder()) {
|
||||
if (p.isValid(strngs, controller, hostCard, null)) {
|
||||
if (p.isValid(strngs, controller, hostCard, stAb)) {
|
||||
players.add(p);
|
||||
}
|
||||
}
|
||||
@@ -983,13 +983,13 @@ public final class StaticAbilityContinuous {
|
||||
} else if (params.get("Affected").contains("EquippedBy")) {
|
||||
affectedCards = new CardCollection(hostCard.getEquipping());
|
||||
} else if (params.get("Affected").equals("EffectSource")) {
|
||||
affectedCards = new CardCollection(AbilityUtils.getDefinedCards(hostCard, params.get("Affected"), null));
|
||||
affectedCards = new CardCollection(AbilityUtils.getDefinedCards(hostCard, params.get("Affected"), stAb));
|
||||
return affectedCards;
|
||||
}
|
||||
}
|
||||
|
||||
if (params.containsKey("Affected")) {
|
||||
affectedCards = CardLists.getValidCards(affectedCards, params.get("Affected").split(","), controller, hostCard, null);
|
||||
affectedCards = CardLists.getValidCards(affectedCards, params.get("Affected").split(","), controller, hostCard, stAb);
|
||||
}
|
||||
affectedCards.removeAll((List<?>) stAb.getIgnoreEffectCards());
|
||||
return affectedCards;
|
||||
|
||||
@@ -55,7 +55,6 @@ public class TriggerCounterRemoved extends Trigger {
|
||||
* @param runParams*/
|
||||
@Override
|
||||
public final boolean performTest(final Map<AbilityKey, Object> runParams) {
|
||||
final Card addedTo = (Card) runParams.get(AbilityKey.Card);
|
||||
final CounterType addedType = (CounterType) runParams.get(AbilityKey.CounterType);
|
||||
final Integer addedNewCounterAmount = (Integer) runParams.get(AbilityKey.NewCounterAmount);
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ public class TriggerCounterRemovedOnce extends Trigger {
|
||||
* @param runParams*/
|
||||
@Override
|
||||
public final boolean performTest(final Map<AbilityKey, Object> runParams) {
|
||||
final Card removedFrom = (Card) runParams.get(AbilityKey.Card);
|
||||
final CounterType removedType = (CounterType) runParams.get(AbilityKey.CounterType);
|
||||
|
||||
if (!matchesValidParam("ValidCard", runParams.get(AbilityKey.Card))) {
|
||||
|
||||
@@ -83,7 +83,14 @@ public class TriggerTapsForMana extends Trigger {
|
||||
}
|
||||
String produced = (String) prod;
|
||||
if ("ChosenColor".equals(getParam("Produced"))) {
|
||||
if (!this.getHostCard().hasChosenColor() || !produced.contains(MagicColor.toShortString(this.getHostCard().getChosenColor()))) {
|
||||
boolean found = false;
|
||||
for (String color : this.getChosenColors()) {
|
||||
if (produced.contains(MagicColor.toShortString(color))) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
} else if (!produced.contains(MagicColor.toShortString(this.getParam("Produced")))) {
|
||||
|
||||
@@ -51,9 +51,6 @@ public enum TrackableProperty {
|
||||
AssignedDamage(TrackableTypes.IntegerType),
|
||||
LethalDamage(TrackableTypes.IntegerType),
|
||||
ShieldCount(TrackableTypes.IntegerType),
|
||||
ChosenType(TrackableTypes.StringType),
|
||||
ChosenType2(TrackableTypes.StringType),
|
||||
ChosenColors(TrackableTypes.StringListType),
|
||||
ChosenCards(TrackableTypes.CardViewCollectionType),
|
||||
ChosenNumber(TrackableTypes.StringType),
|
||||
ChosenPlayer(TrackableTypes.PlayerViewType),
|
||||
|
||||
@@ -482,7 +482,7 @@ public class GameSimulatorTest extends SimulationTestCase {
|
||||
Player p = game.getPlayers().get(1);
|
||||
Card bear = addCard(bearCardName, p);
|
||||
Card hall = addCard("Hall of Triumph", p);
|
||||
hall.setChosenColors(Lists.newArrayList("green"));
|
||||
hall.setChosenColors(Lists.newArrayList("green"), hall.getFirstSpellAbility());
|
||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
||||
game.getAction().checkStateEffects(true);
|
||||
assertEquals(3, bear.getNetToughness());
|
||||
|
||||
@@ -80,7 +80,7 @@ import forge.util.collect.FCollectionView;
|
||||
/**
|
||||
* Default harmless implementation for tests.
|
||||
* Test-specific behaviour can easily be added by mocking (parts of) this class.
|
||||
*
|
||||
*
|
||||
* Note that the current PlayerController implementations seem to be responsible for handling some game logic,
|
||||
* and even aside from that, they are theoretically capable of making illegal choices (which are then not blocked by the real game logic).
|
||||
* Test cases that need to override the default behaviour of this class should make sure to do so in a way that does not invalidate their correctness.
|
||||
@@ -281,7 +281,7 @@ public class PlayerControllerForTests extends PlayerController {
|
||||
|
||||
@Override
|
||||
public CardCollection chooseCardsToDiscardFrom(Player playerDiscard, SpellAbility sa, CardCollection validCards, int min, int max) {
|
||||
return chooseItems(validCards, min);
|
||||
return chooseItems((CardCollectionView)validCards, min);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -416,7 +416,7 @@ public class PlayerControllerForTests extends PlayerController {
|
||||
@Override
|
||||
public List<SpellAbility> chooseSpellAbilityToPlay() {
|
||||
//TODO: This method has to return the spellability chosen by player
|
||||
// It should not play the sa right from here. The code has been left as it is to quickly adapt to changed playercontroller interface
|
||||
// It should not play the sa right from here. The code has been left as it is to quickly adapt to changed playercontroller interface
|
||||
if (playerActions != null) {
|
||||
CastSpellFromHandAction castSpellFromHand = playerActions.getNextActionIfApplicable(player, getGame(), CastSpellFromHandAction.class);
|
||||
if (castSpellFromHand != null) {
|
||||
@@ -470,7 +470,7 @@ public class PlayerControllerForTests extends PlayerController {
|
||||
public byte chooseColor(String message, SpellAbility sa, ColorSet colors) {
|
||||
return Iterables.getFirst(colors, MagicColor.WHITE);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public byte chooseColorAllowColorless(String message, Card card, ColorSet colors) {
|
||||
return Iterables.getFirst(colors, (byte)0);
|
||||
@@ -483,6 +483,13 @@ public class PlayerControllerForTests extends PlayerController {
|
||||
return (CardCollection)items.subList(0, Math.max(amount, items.size()));
|
||||
}
|
||||
|
||||
private <T> List<T> chooseItems(List<T> items, int amount) {
|
||||
if (items == null || items.isEmpty()) {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
return items.subList(0, Math.max(amount, items.size()));
|
||||
}
|
||||
|
||||
private <T> T chooseItem(Iterable<T> items) {
|
||||
if (items == null) {
|
||||
return null;
|
||||
@@ -497,8 +504,8 @@ public class PlayerControllerForTests extends PlayerController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseSomeType(String kindOfType, SpellAbility sa, Collection<String> validTypes, List<String> invalidTypes, boolean isOptional) {
|
||||
return chooseItem(validTypes);
|
||||
public List<String> chooseSomeType(String kindOfType, SpellAbility sa, int min, int max, List<String> validTypes) {
|
||||
return chooseItems(validTypes, min);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -545,7 +552,7 @@ public class PlayerControllerForTests extends PlayerController {
|
||||
ComputerUtil.playStack(sa, player, getGame());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void prepareSingleSa(final Card host, final SpellAbility sa, boolean isMandatory){
|
||||
if (sa.hasParam("TargetingPlayer")) {
|
||||
Player targetingPlayer = AbilityUtils.getDefinedPlayers(host, sa.getParam("TargetingPlayer"), sa).get(0);
|
||||
@@ -577,7 +584,7 @@ public class PlayerControllerForTests extends PlayerController {
|
||||
} else {
|
||||
ComputerUtil.playStack(tgtSA, player, getGame());
|
||||
}
|
||||
} else
|
||||
} else
|
||||
return false; // didn't play spell
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -4,10 +4,8 @@ Types:Creature Angel
|
||||
PT:5/6
|
||||
K:Flying
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, you may exile up to three other target creatures from the battlefield and/or creature cards from graveyards.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME leaves the battlefield, return the exiled cards to their owners' hands.
|
||||
SVar:TrigExile:DB$ ChangeZone | TargetMin$ 0 | TargetMax$ 3 | IsCurse$ True | ValidTgts$ Creature.Other | TgtPrompt$ Choose another target creature | RememberChanged$ True | Origin$ Battlefield,Graveyard | Destination$ Exile
|
||||
SVar:TrigReturn:DB$ ChangeZone | Defined$ Remembered | Origin$ Exile | Destination$ Hand | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:TrigExile:DB$ ChangeZone | TargetMin$ 0 | TargetMax$ 3 | IsCurse$ True | ValidTgts$ Creature.Other | TgtPrompt$ Choose another target creature | Origin$ Battlefield,Graveyard | Destination$ Exile
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When CARDNAME leaves the battlefield, return the exiled cards to their owners' hands.
|
||||
SVar:TrigReturn:DB$ ChangeZone | Defined$ ExiledWith | Origin$ Exile | Destination$ Hand
|
||||
SVar:PlayMain1:TRUE
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/angel_of_serenity.jpg
|
||||
Oracle:Flying\nWhen Angel of Serenity enters the battlefield, you may exile up to three other target creatures from the battlefield and/or creature cards from graveyards.\nWhen Angel of Serenity leaves the battlefield, return the exiled cards to their owners' hands.
|
||||
|
||||
@@ -2,15 +2,9 @@ Name:Ashiok, Nightmare Weaver
|
||||
ManaCost:1 U B
|
||||
Types:Legendary Planeswalker Ashiok
|
||||
Loyalty:3
|
||||
A:AB$ Dig | Cost$ AddCounter<2/LOYALTY> | Planeswalker$ True | ValidTgts$ Opponent | DigNum$ 3 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | SpellDescription$ Exile the top three cards of target opponent's library.
|
||||
A:AB$ ChooseCard | Cost$ SubCounter<X/LOYALTY> | Choices$ Creature.cmcEQX+IsRemembered+ExiledWithSource | ChoiceZone$ Exile | Planeswalker$ True | SubAbility$ DBChangeZone | AILogic$ Ashiok | SpellDescription$ Put a creature card with converted mana cost X exiled with CARDNAME onto the battlefield under your control. That creature is a Nightmare in addition to its other types.
|
||||
SVar:DBChangeZone:DB$ ChangeZone | Defined$ ChosenCard | Origin$ Exile | Destination$ Battlefield | ChangeType$ Creature.cmcEQX+IsRemembered+ExiledWithSource | ChangeNum$ 1 | GainControl$ True | SubAbility$ DBAnimate
|
||||
SVar:DBAnimate:DB$ Animate | Defined$ ChosenCard | Types$ Nightmare | Permanent$ True | SubAbility$ DBCleanMinus
|
||||
SVar:DBCleanMinus:DB$ Cleanup | ForgetDefined$ ChosenCard | ClearChosenCard$ True
|
||||
A:AB$ Dig | Cost$ AddCounter<2/LOYALTY> | Planeswalker$ True | ValidTgts$ Opponent | DigNum$ 3 | ChangeNum$ All | DestinationZone$ Exile | SpellDescription$ Exile the top three cards of target opponent's library.
|
||||
A:AB$ ChangeZone | Cost$ SubCounter<X/LOYALTY> | Planeswalker$ True | Hidden$ True | Origin$ Exile | Destination$ Battlefield | ChangeType$ Creature.cmcEQX+ExiledWithSource | ChangeNum$ 1 | GainControl$ True | AnimateSubAbility$ DBAnimate | AILogic$ Ashiok | Mandatory$ True | StackDescription$ SpellDescription | SpellDescription$ Put a creature card exiled with CARDNAME onto the battlefield under your control.
|
||||
SVar:DBAnimate:DB$ Animate | Defined$ Remembered | Types$ Nightmare | Permanent$ True
|
||||
SVar:X:Count$xPaid
|
||||
A:AB$ ChangeZoneAll | Cost$ SubCounter<10/LOYALTY> | ChangeType$ Card.OppCtrl | Origin$ Graveyard,Hand | Destination$ Exile | RememberChanged$ True | Planeswalker$ True | Ultimate$ True | SpellDescription$ Exile all cards from all opponents' hands and graveyards.
|
||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
|
||||
SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
A:AB$ ChangeZoneAll | Cost$ SubCounter<10/LOYALTY> | ChangeType$ Card.OppCtrl | Origin$ Graveyard,Hand | Destination$ Exile | Planeswalker$ True | Ultimate$ True | SpellDescription$ Exile all cards from all opponents' hands and graveyards.
|
||||
Oracle:[+2]: Exile the top three cards of target opponent's library.\n[−X]: Put a creature card with converted mana cost X exiled with Ashiok, Nightmare Weaver onto the battlefield under your control. That creature is a Nightmare in addition to its other types.\n[−10]: Exile all cards from all opponents' hands and graveyards.
|
||||
|
||||
@@ -3,9 +3,8 @@ ManaCost:2 U U
|
||||
Types:Enchantment
|
||||
K:Flash
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, exile target spell.
|
||||
S:Mode$ CantBeCast | ValidCard$ Card.nonLand+sharesNameWith Remembered.ExiledWithSource | Caster$ Opponent | Description$ Your opponents can't cast spells with the same name as the card exiled by CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigBounce | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME leaves the battlefield, return the exiled card to its owner's hand.
|
||||
SVar:TrigExile:DB$ChangeZone | TargetType$ Spell | ValidTgts$ Card | TgtZone$ Stack | Origin$ Stack | Fizzle$ True | Mandatory$ True | Destination$ Exile | IsCurse$ True | TgtPrompt$ Choose target spell | RememberChanged$ True
|
||||
SVar:TrigBounce:DB$ChangeZone | Origin$ Exile | Destination$ Hand | Defined$ Remembered | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:TrigExile:DB$ ChangeZone | TargetType$ Spell | ValidTgts$ Card | TgtZone$ Stack | Origin$ Stack | Fizzle$ True | Mandatory$ True | Destination$ Exile | IsCurse$ True | TgtPrompt$ Choose target spell
|
||||
S:Mode$ CantBeCast | ValidCard$ Card.nonLand+sharesNameWith ExiledWith | Caster$ Opponent | Description$ Your opponents can't cast spells with the same name as the card exiled by CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigBounce | TriggerDescription$ When CARDNAME leaves the battlefield, return the exiled card to its owner's hand.
|
||||
SVar:TrigBounce:DB$ ChangeZone | Defined$ ExiledWith | Origin$ Exile | Destination$ Hand
|
||||
Oracle:Flash\nWhen Ashiok's Erasure enters the battlefield, exile target spell.\nYour opponents can't cast spells with the same name as the exiled card.\nWhen Ashiok's Erasure leaves the battlefield, return the exiled card to its owner's hand.
|
||||
|
||||
@@ -2,16 +2,11 @@ Name:Azor's Gateway
|
||||
ManaCost:2
|
||||
Types:Legendary Artifact
|
||||
A:AB$ Draw | Cost$ 1 T | NumCards$ 1 | SubAbility$ DBExile | SpellDescription$ Draw a card, then exile a card from your hand. If cards with five or more different converted mana costs are exiled with CARDNAME, you gain 5 life, untap CARDNAME, and transform it.
|
||||
SVar:DBExile:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | ChangeType$ Card | ChangeNum$ 1 | Mandatory$ True | RememberChanged$ True | SubAbility$ DBGainLife
|
||||
SVar:DBExile:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | ChangeType$ Card | ChangeNum$ 1 | Mandatory$ True | SubAbility$ DBGainLife
|
||||
SVar:DBGainLife:DB$ GainLife | LifeAmount$ 5 | SubAbility$ DBUntap | ConditionCheckSVar$ Y | ConditionSVarCompare$ GE5
|
||||
SVar:DBUntap:DB$ Untap | Defined$ Self | SubAbility$ DBTransform | ConditionCheckSVar$ Y | ConditionSVarCompare$ GE5
|
||||
SVar:DBTransform:DB$ SetState | Defined$ Self | Mode$ Transform | ConditionCheckSVar$ Y | ConditionSVarCompare$ GE5
|
||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
|
||||
SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:Y:Remembered$DifferentCMC
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/azors_gateway.jpg
|
||||
SVar:Y:ExiledWith$DifferentCMC
|
||||
AlternateMode:DoubleFaced
|
||||
Oracle:{1}, {T}: Draw a card, then exile a card from your hand. If cards with five or more different converted mana costs are exiled with Azor's Gateway, you gain 5 life, untap Azor's Gateway, and transform it.
|
||||
|
||||
@@ -23,5 +18,4 @@ Colors:colorless
|
||||
Types:Land
|
||||
A:AB$ Mana | Cost$ T | Produced$ Any | Amount$ X | SpellDescription$ Add X mana of any one color, where X is your life total.
|
||||
SVar:X:Count$YourLifeTotal
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/sanctum_of_the_sun.jpg
|
||||
Oracle:(Transforms from Azor's Gateway.)\n{T}: Add X mana of any one color, where X is your life total.
|
||||
|
||||
@@ -3,13 +3,7 @@ ManaCost:1 U B
|
||||
Types:Creature Human Rogue
|
||||
PT:0/3
|
||||
A:AB$ Draw | Cost$ T | NumCards$ 1 | SubAbility$ DBExile | SpellDescription$ Draw a card, then exile a card from your hand face down.
|
||||
SVar:DBExile:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | ChangeType$ Card | ChangeNum$ 1 | ExileFaceDown$ True | Mandatory$ True | RememberChanged$ True
|
||||
S:Mode$ Continuous | Affected$ Card.IsRemembered+ExiledWithSource | AffectedZone$ Exile | MayLookAt$ You | Description$ You may look at cards exiled with CARDNAME.
|
||||
A:AB$ ChooseCard | Cost$ U B T | Defined$ You | Amount$ 1 | Mandatory$ True | AILogic$ AtLeast1 | ChoiceTitle$ Choose a card to put into your hand | Choices$ Card.IsRemembered+ExiledWithSource | ChoiceZone$ Exile | SubAbility$ MoveChosen | SpellDescription$ Return a card exiled with CARDNAME to its owner's hand.
|
||||
SVar:MoveChosen:DB$ ChangeZone | Origin$ Exile | Destination$ Hand | Defined$ ChosenCard | ForgetChanged$ True | SubAbility$ DBCleanupChosen
|
||||
SVar:DBCleanupChosen:DB$ Cleanup | ClearChosenCard$ True
|
||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
|
||||
SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:DBExile:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | ChangeType$ Card | ChangeNum$ 1 | ExileFaceDown$ True | Mandatory$ True
|
||||
S:Mode$ Continuous | Affected$ Card.ExiledWithSource | AffectedZone$ Exile | MayLookAt$ You | Description$ You may look at cards exiled with CARDNAME.
|
||||
A:AB$ ChangeZone | Cost$ U B T | Hidden$ True | Origin$ Exile | Destination$ Hand | ChangeType$ Creature.ExiledWithSource | ChangeNum$ 1 | Mandatory$ True | StackDescription$ SpellDescription | SpellDescription$ Return a card exiled with CARDNAME to its owner's hand.
|
||||
Oracle:{T}: Draw a card, then exile a card from your hand face down.\nYou may look at cards exiled with Bane Alley Broker.\n{U}{B}, {T}: Return a card exiled with Bane Alley Broker to its owner's hand.
|
||||
|
||||
@@ -5,4 +5,4 @@ T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.S
|
||||
SVar:TrigExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Permanent.nonLand+OppCtrl | TgtPrompt$ Select target nonland permanent an opponent controls | UntilHostLeavesPlay$ True
|
||||
SVar:PlayMain1:TRUE
|
||||
SVar:OblivionRing:TRUE
|
||||
Oracle:When Banishing Light enters the battlefield, exile target nonland permanent an opponent controls until Banishing Light leaves the battlefield.
|
||||
Oracle:When Banishing Light enters the battlefield, exile target nonland permanent an opponent controls until Banishing Light leaves the battlefield. (That permanent returns under its owner's control.)
|
||||
|
||||
@@ -3,17 +3,11 @@ ManaCost:3 W
|
||||
Types:Creature Vampire Cleric
|
||||
PT:1/1
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, exile target creature an opponent controls until CARDNAME leaves the battlefield.
|
||||
SVar:TrigExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | ConditionPresent$ Card.Self | RememberChanged$ True | SubAbility$ DBEffect
|
||||
SVar:DBEffect:DB$ Effect | Triggers$ ComeBack | RememberObjects$ Targeted | ImprintCards$ Self | ConditionPresent$ Card.Self | Duration$ Permanent | ForgetOnMoved$ Exile
|
||||
SVar:ComeBack:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.IsImprinted | Execute$ TrigReturn | TriggerZones$ Command | TriggerController$ TriggeredCardController | Static$ True | TriggerDescription$ That creature is exiled until EFFECTSOURCE leaves the battlefield
|
||||
SVar:TrigReturn:DB$ ChangeZoneAll | Origin$ Exile | Destination$ Battlefield | ChangeType$ Card.IsRemembered | SubAbility$ ExileSelf
|
||||
SVar:ExileSelf:DB$ ChangeZone | Origin$ Command | Destination$ Exile | Defined$ Self
|
||||
SVar:TrigExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | UntilHostLeavesPlay$ True
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigPump | TriggerDescription$ Whenever CARDNAME attacks, target Vampire gets +X/+X until end of turn, where X is the power of the exiled card.
|
||||
SVar:TrigPump:DB$ Pump | ValidTgts$ Permanent.Vampire | TgtPrompt$ Select target Vampire | NumAtt$ X | NumDef$ X
|
||||
SVar:X:Remembered$CardPower
|
||||
SVar:X:ExiledWith$CardPower
|
||||
// Release notes indicate that this effect should work with Vehicle cards.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:PlayMain1:TRUE
|
||||
DeckHints:Type$Vampire
|
||||
Oracle:When Bishop of Binding enters the battlefield, exile target creature an opponent controls until Bishop of Binding leaves the battlefield.\nWhenever Bishop of Binding attacks, target Vampire gets +X/+X until end of turn, where X is the power of the exiled card.
|
||||
Oracle:When Bishop of Binding enters the battlefield, exile target creature an opponent controls until Bishop of Binding leaves the battlefield.\nWhenever Bishop of Binding attacks, target Vampire gets +X/+X until end of turn, where X is the power of the exiled card.
|
||||
|
||||
@@ -4,12 +4,9 @@ Types:Artifact Creature Construct
|
||||
PT:1/1
|
||||
K:Haste
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigExile | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME attacks, exile the top card of your library face down. (You can't look at it.)
|
||||
SVar:TrigExile:DB$ Dig | Defined$ You | DigNum$ 1 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | ExileFaceDown$ True | NoReveal$ True
|
||||
A:AB$ ChangeZoneAll | Cost$ R Discard<0/Hand> Sac<1/CARDNAME> | ChangeType$ Card.IsRemembered+ExiledWithSource | Origin$ Exile | Destination$ Hand | AILogic$ DiscardAllAndRetExiled.minAdv2 | SpellDescription$ Put all cards exiled with CARDNAME into their owners' hands.
|
||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
|
||||
SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:TrigExile:DB$ Dig | Defined$ You | DigNum$ 1 | ChangeNum$ All | DestinationZone$ Exile | ExileFaceDown$ True | NoReveal$ True
|
||||
A:AB$ ChangeZone | Cost$ R Discard<1/Hand> Sac<1/CARDNAME> | Defined$ ExiledWith | Origin$ Exile | Destination$ Hand | AILogic$ DiscardAllAndRetExiled.minAdv2 | SpellDescription$ Put all cards exiled with CARDNAME into their owners' hands.
|
||||
DeckNeeds:Color$Red
|
||||
SVar:AISkipDiscardCostCheck:TRUE
|
||||
AI:RemoveDeck:Random
|
||||
Oracle:Haste\nWhenever Bomat Courier attacks, exile the top card of your library face down. (You can't look at it.)\n{R}, Discard your hand, Sacrifice Bomat Courier: Put all cards exiled with Bomat Courier into their owners' hands.
|
||||
|
||||
@@ -4,7 +4,7 @@ Types:Legendary Creature Human Minion
|
||||
PT:3/3
|
||||
S:Mode$ Continuous | Affected$ Creature.Nightmare | AddPower$ 1 | AddToughness$ 1 | Description$ Nightmare creatures get +1/+1.
|
||||
A:AB$ ChangeZone | Cost$ B B B PayLife<3> | Origin$ Graveyard | Destination$ Battlefield | GainControl$ True | TgtPrompt$ Select target creature card in a graveyard | ValidTgts$ Creature | ChangeNum$ 1 | AnimateSubAbility$ DBAnimate | SpellDescription$ Put target creature card from a graveyard onto the battlefield under your control. That creature is black and is a Nightmare in addition to its other creature types.
|
||||
SVar:DBAnimate:DB$ Animate | Defined$ Targeted | Types$ Nightmare | Colors$ Black | Permanent$ True | OverwriteColors$ True
|
||||
SVar:DBAnimate:DB$ Animate | Defined$ Remembered | Types$ Nightmare | Colors$ Black | Permanent$ True | OverwriteColors$ True
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigExile | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME leaves the battlefield, exile all Nightmares.
|
||||
SVar:TrigExile:DB$ ChangeZoneAll | Origin$ Battlefield | Destination$ Exile | ChangeType$ Nightmare
|
||||
SVar:PlayMain1:TRUE
|
||||
|
||||
@@ -2,13 +2,8 @@ Name:Chrome Mox
|
||||
ManaCost:0
|
||||
Types:Artifact
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | OptionalDecider$ You | Execute$ TrigExile | TriggerDescription$ Imprint — When CARDNAME enters the battlefield, you may exile a nonartifact, nonland card from your hand.
|
||||
SVar:TrigExile:DB$ChangeZone | Imprint$ True | Origin$ Hand | Destination$ Exile | ChangeType$ Card.nonArtifact+nonLand | ChangeNum$ 1
|
||||
A:AB$ ManaReflected | Cost$ T | Valid$ Defined.Imprinted | ColorOrType$ Color | ReflectProperty$ Is | SpellDescription$ Add one mana of any of the exiled card's colors.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | ValidCard$ Card.Self | Destination$ Any | Execute$ DBCleanup | Static$ True
|
||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsImprinted+ExiledWithSource | Execute$ DBForget
|
||||
SVar:DBForget:DB$ Pump | ForgetImprinted$ TriggeredCard
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearImprinted$ True
|
||||
SVar:TrigExile:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | ChangeType$ Card.nonArtifact+nonLand | ChangeNum$ 1
|
||||
A:AB$ ManaReflected | Cost$ T | Valid$ ExiledWith | ColorOrType$ Color | ReflectProperty$ Is | SpellDescription$ Add one mana of any of the exiled card's colors.
|
||||
SVar:NeedsToPlayVar:Z GE1
|
||||
SVar:Z:Count$ValidHand Card.nonArtifact+nonColorless+nonLand+YouOwn
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/chrome_mox.jpg
|
||||
Oracle:Imprint — When Chrome Mox enters the battlefield, you may exile a nonartifact, nonland card from your hand.\n{T}: Add one mana of any of the exiled card's colors.
|
||||
Oracle:Imprint — When Chrome Mox enters the battlefield, you may exile a nonartifact, nonland card from your hand.\n{T}: Add one mana of any of the exiled card's colors.
|
||||
|
||||
@@ -4,10 +4,6 @@ Types:Legendary Creature Human Wizard
|
||||
PT:2/3
|
||||
T:Mode$ SpellCast | ValidCard$ Card.Blue | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ ExileTop | TriggerDescription$ Whenever you cast a blue spell, exile the top card of target player's library.
|
||||
T:Mode$ SpellCast | ValidCard$ Card.Black | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ ExileTop | TriggerDescription$ Whenever you cast a black spell, exile the top card of target player's library.
|
||||
SVar:ExileTop:DB$ Dig | DigNum$ 1 | ChangeNum$ All | ValidTgts$ Player | TgtPrompt$ Choose a player | DestinationZone$ Exile | RememberChanged$ True
|
||||
S:Mode$ CantBeCast | ValidCard$ Card.nonLand+sharesNameWith Remembered.ExiledWithSource | Caster$ Opponent | Description$ Your opponents can't cast spells with the same name as a card exiled with CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
|
||||
SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:ExileTop:DB$ Dig | DigNum$ 1 | ChangeNum$ All | ValidTgts$ Player | TgtPrompt$ Choose a player | DestinationZone$ Exile
|
||||
S:Mode$ CantBeCast | ValidCard$ Card.nonLand+sharesNameWith ExiledWith | Caster$ Opponent | Description$ Your opponents can't cast spells with the same name as a card exiled with CARDNAME.
|
||||
Oracle:Whenever you cast a blue spell, exile the top card of target player's library.\nWhenever you cast a black spell, exile the top card of target player's library.\nYour opponents can't cast spells with the same name as a card exiled with Circu, Dimir Lobotomist.
|
||||
|
||||
@@ -3,11 +3,9 @@ ManaCost:5
|
||||
Types:Artifact Creature Shapeshifter
|
||||
PT:2/2
|
||||
T:Mode$ ChangesZone | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDig | TriggerDescription$ Imprint — When Clone Shell enters the battlefield, look at the top four cards of your library, exile one face down, then put the rest on the bottom of your library in any order.
|
||||
SVar:TrigDig:DB$ Dig | Defined$ You | DigNum$ 4 | DestinationZone$ Exile | ExileFaceDown$ True | Imprint$ True
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigFaceUp | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, turn the exiled card face up. If it's a creature card, put it onto the battlefield under your control.
|
||||
SVar:TrigFaceUp:DB$ SetState | Defined$ Imprinted | SubAbility$ DBChangeZone | Mode$ TurnFace
|
||||
SVar:DBChangeZone:DB$ ChangeZone | Defined$ Imprinted | Origin$ Exile | Destination$ Battlefield | ConditionDefined$ Imprinted | ConditionPresent$ Creature | GainControl$ True | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearImprinted$ True
|
||||
SVar:TrigDig:DB$ Dig | Defined$ You | DigNum$ 4 | DestinationZone$ Exile | ExileFaceDown$ True
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigFaceUp | TriggerDescription$ When CARDNAME dies, turn the exiled card face up. If it's a creature card, put it onto the battlefield under your control.
|
||||
SVar:TrigFaceUp:DB$ SetState | Defined$ ExiledWith | Mode$ TurnFace | SubAbility$ DBChangeZone
|
||||
SVar:DBChangeZone:DB$ ChangeZone | Defined$ ExiledWith.Creature | Origin$ Exile | Destination$ Battlefield
|
||||
SVar:SacMe:5
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/clone_shell.jpg
|
||||
Oracle:Imprint — When Clone Shell enters the battlefield, look at the top four cards of your library, exile one face down, then put the rest on the bottom of your library in any order.\nWhen Clone Shell dies, turn the exiled card face up. If it's a creature card, put it onto the battlefield under your control.
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
Name:Cold Storage
|
||||
ManaCost:4
|
||||
Types:Artifact
|
||||
A:AB$ ChangeZone | Cost$ 3 | ValidTgts$ Creature.YouCtrl | Origin$ Battlefield | Destination$ Exile | TgtPrompt$ Select target creature you control | RememberTargets$ True | SpellDescription$ Exile target creature you control.
|
||||
A:AB$ ChangeZoneAll | Cost$ Sac<1/CARDNAME> | ChangeType$ Card.Creature+IsRemembered+ExiledWithSource | Origin$ Exile | Destination$ Battlefield | GainControl$ True | SubAbility$ DBCleanup | SpellDescription$ Return each creature card exiled with CARDNAME to the battlefield under your control.
|
||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
|
||||
SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup
|
||||
SVar:DBCleanup:DB$Cleanup | ClearRemembered$ True
|
||||
A:AB$ ChangeZone | Cost$ 3 | ValidTgts$ Creature.YouCtrl | Origin$ Battlefield | Destination$ Exile | TgtPrompt$ Select target creature you control | SpellDescription$ Exile target creature you control.
|
||||
A:AB$ ChangeZone | Cost$ Sac<1/CARDNAME> | Defined$ ExiledWith | Origin$ Exile | Destination$ Battlefield | GainControl$ True | SpellDescription$ Return each creature card exiled with CARDNAME to the battlefield under your control.
|
||||
SVar:NonStackingEffect:True
|
||||
AI:RemoveDeck:All
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/cold_storage.jpg
|
||||
Oracle:{3}: Exile target creature you control.\nSacrifice Cold Storage: Return each creature card exiled with Cold Storage to the battlefield under your control.
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
Name:Colfenor's Plans
|
||||
ManaCost:2 B B
|
||||
Types:Enchantment
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, exile the top seven cards of your library face down. You may look at the cards exiled with CARDNAME, and you may play lands and cast spells from among those cards.
|
||||
SVar:TrigExile:DB$ Dig | Defined$ You | DigNum$ 7 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | ExileFaceDown$ True | NoReveal$ True
|
||||
S:Mode$ Continuous | Affected$ Card.IsRemembered+ExiledWithSource | AffectedZone$ Exile | MayPlay$ True | MayLookAt$ You | Description$ You may look at the cards exiled with CARDNAME, and you may play lands and cast spells from among those cards.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, exile the top seven cards of your library face down.
|
||||
SVar:TrigExile:DB$ Dig | Defined$ You | DigNum$ 7 | ChangeNum$ All | DestinationZone$ Exile | ExileFaceDown$ True | NoReveal$ True
|
||||
R:Event$ BeginPhase | ActiveZones$ Battlefield | ValidPlayer$ You | Phase$ Draw | Skip$ True | Description$ Skip your draw step.
|
||||
S:Mode$ Continuous | Affected$ Card.ExiledWithSource | AffectedZone$ Exile | MayPlay$ True | MayLookAt$ You | Description$ You may look at the cards exiled with CARDNAME, and you may play lands and cast spells from among those cards.
|
||||
S:Mode$ CantBeCast | ValidCard$ Card | Caster$ You | NumLimitEachTurn$ 1 | Description$ You can't cast more than one spell each turn.
|
||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
|
||||
SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
AI:RemoveDeck:All
|
||||
Oracle:When Colfenor's Plans enters the battlefield, exile the top seven cards of your library face down.\nYou may look at the cards exiled with Colfenor's Plans, and you may play lands and cast spells from among those cards.\nSkip your draw step.\nYou can't cast more than one spell each turn.
|
||||
|
||||
@@ -2,12 +2,7 @@ Name:Dark Impostor
|
||||
ManaCost:2 B
|
||||
Types:Creature Vampire Assassin
|
||||
PT:2/2
|
||||
S:Mode$ Continuous | Affected$ Card.Self | EffectZone$ Battlefield | GainsAbilitiesOf$ Creature.IsRemembered+ExiledWithSource | GainsAbilitiesOfZones$ Exile | Description$ CARDNAME has all activated abilities of all creature cards exiled with it.
|
||||
A:AB$ ChangeZone | Cost$ 4 B B | ValidTgts$ Creature | Origin$ Battlefield | Destination$ Exile | TgtPrompt$ Select target creature | SubAbility$ DBCounter | RememberChanged$ True | SpellDescription$ Exile target creature and put a +1/+1 counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
|
||||
SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | ValidCard$ Card.Self | Destination$ Any | Execute$ DBCleanup | Static$ True
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
S:Mode$ Continuous | Affected$ Card.Self | EffectZone$ Battlefield | GainsAbilitiesOf$ Creature.ExiledWithSource | GainsAbilitiesOfZones$ Exile | Description$ CARDNAME has all activated abilities of all creature cards exiled with it.
|
||||
A:AB$ ChangeZone | Cost$ 4 B B | ValidTgts$ Creature | Origin$ Battlefield | Destination$ Exile | TgtPrompt$ Select target creature | SubAbility$ DBCounter | SpellDescription$ Exile target creature and put a +1/+1 counter on CARDNAME.
|
||||
SVar:DBCounter:DB$PutCounter | CounterType$ P1P1 | CounterNum$ 1 | Defined$ Self
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/dark_impostor.jpg
|
||||
Oracle:{4}{B}{B}: Exile target creature and put a +1/+1 counter on Dark Impostor.\nDark Impostor has all activated abilities of all creature cards exiled with it.
|
||||
|
||||
@@ -2,11 +2,11 @@ Name:Day of the Dragons
|
||||
ManaCost:4 U U U
|
||||
Types:Enchantment
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, exile all creatures you control. Then create that many 5/5 red Dragon creature tokens with flying. When CARDNAME leaves the battlefield, sacrifice all Dragons you control. Then return the exiled cards to the battlefield under your control.
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Battlefield | Destination$ Any | Execute$ TrigSacrifice | Secondary$ True | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME leaves the battlefield, sacrifice all Dragons you control. Then return the exiled cards to the battlefield under your control.
|
||||
SVar:TrigExile:DB$ChangeZoneAll | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | ForgetOtherRemembered$ True | ChangeType$ Creature.YouCtrl | SubAbility$ DBToken
|
||||
SVar:TrigSacrifice:DB$SacrificeAll | ValidCards$ Dragon.YouCtrl | SubAbility$ DBReturn
|
||||
SVar:DBToken:DB$Token | TokenAmount$ X | TokenScript$ r_5_5_dragon_flying | TokenOwner$ You | LegacyImage$ r 5 5 dragon flying scg
|
||||
SVar:DBReturn:DB$ChangeZoneAll | Origin$ Exile | Destination$ Battlefield | ChangeType$ Card.IsRemembered
|
||||
SVar:TrigExile:DB$ ChangeZoneAll | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | ChangeType$ Creature.YouCtrl | SubAbility$ DBToken
|
||||
SVar:DBToken:DB$ Token | TokenAmount$ X | TokenScript$ r_5_5_dragon_flying | TokenOwner$ You | LegacyImage$ r 5 5 dragon flying scg | References$ X | SubAbility$ DBCleanup
|
||||
SVar:X:Remembered$Amount
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/day_of_the_dragons.jpg
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Battlefield | Destination$ Any | Execute$ TrigSacrifice | Secondary$ True | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME leaves the battlefield, sacrifice all Dragons you control. Then return the exiled cards to the battlefield under your control.
|
||||
SVar:TrigSacrifice:DB$ SacrificeAll | ValidCards$ Dragon.YouCtrl | SubAbility$ DBReturn
|
||||
SVar:DBReturn:DB$ ChangeZone | Defined$ ExiledWith | Origin$ Exile | Destination$ Battlefield
|
||||
Oracle:When Day of the Dragons enters the battlefield, exile all creatures you control. Then create that many 5/5 red Dragon creature tokens with flying.\nWhen Day of the Dragons leaves the battlefield, sacrifice all Dragons you control. Then return the exiled cards to the battlefield under your control.
|
||||
|
||||
@@ -4,5 +4,6 @@ Types:Creature Vedalken Wizard
|
||||
PT:1/3
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, exile target nonland permanent an opponent controls and all other nonland permanents that player controls with the same name as that permanent until CARDNAME leaves the battlefield.
|
||||
SVar:TrigExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Permanent.nonLand+OppCtrl | TgtPrompt$ Select target nonland permanent an opponent controls | SubAbility$ DBChangeZoneAll | UntilHostLeavesPlay$ True
|
||||
SVar:DBChangeZoneAll:DB$ ChangeZoneAll | Origin$ Battlefield | Destination$ Exile | ChangeType$ Permanent.nonLand+NotDefinedTargeted+sharesNameWith Targeted+ControlledBy TargetedOrController | UntilHostLeavesPlay$ True
|
||||
SVar:DBChangeZoneAll:DB$ ChangeZoneAll | Origin$ Battlefield | Destination$ Exile | ChangeType$ Card.sharesNameWith ExiledWith+ControlledBy TargetedOrController | UntilHostLeavesPlay$ True | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$Cleanup | ClearRemembered$ True
|
||||
Oracle:When Deputy of Detention enters the battlefield, exile target nonland permanent an opponent controls and all other nonland permanents that player controls with the same name as that permanent until Deputy of Detention leaves the battlefield.
|
||||
|
||||
@@ -2,10 +2,9 @@ Name:Detention Sphere
|
||||
ManaCost:1 W U
|
||||
Types:Enchantment
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | OptionalDecider$ You | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, you may exile target nonland permanent not named CARDNAME and all other permanents with the same name as that permanent.
|
||||
SVar:TrigExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Permanent.nonLand+notnamedDetention Sphere | TgtPrompt$ Choose target nonland permanent not named Detention Sphere | RememberTargets$ True | ForgetOtherTargets$ True | SubAbility$ DBChangeZoneAll
|
||||
SVar:DBChangeZoneAll:DB$ ChangeZoneAll | ChangeType$ Remembered.sameName | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True
|
||||
SVar:TrigExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Permanent.nonLand+notnamedDetention Sphere | TgtPrompt$ Choose target nonland permanent not named Detention Sphere | SubAbility$ DBChangeZoneAll
|
||||
SVar:DBChangeZoneAll:DB$ ChangeZoneAll | Origin$ Battlefield | Destination$ Exile | ChangeType$ Card.sharesNameWith ExiledWith
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When CARDNAME leaves the battlefield, return the exiled cards to the battlefield under their owner's control.
|
||||
SVar:TrigReturn:DB$ ChangeZoneAll | ChangeType$ Card.IsRemembered | Origin$ Exile | Destination$ Battlefield
|
||||
SVar:TrigReturn:DB$ ChangeZone | Defined$ ExiledWith | Origin$ Exile | Destination$ Battlefield
|
||||
SVar:OblivionRing:TRUE
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/detention_sphere.jpg
|
||||
Oracle:When Detention Sphere enters the battlefield, you may exile target nonland permanent not named Detention Sphere and all other permanents with the same name as that permanent.\nWhen Detention Sphere leaves the battlefield, return the exiled cards to the battlefield under their owner's control.
|
||||
|
||||
@@ -3,14 +3,8 @@ ManaCost:3 U
|
||||
Types:Creature Human Wizard
|
||||
PT:1/1
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | OptionalDecider$ You | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, you may exile an instant card from your hand.
|
||||
SVar:TrigExile:DB$ ChangeZone | RememberChanged$ True | Origin$ Hand | Destination$ Exile | ChangeType$ Instant | ChangeNum$ 1
|
||||
A:AB$ Play | Cost$ X T | Valid$ Card.IsRemembered+ExiledWithSource | ValidZone$ Exile | Amount$ All | CopyOnce$ True | WithoutManaCost$ True | Optional$ True | CopyCard$ True | SpellDescription$ Copy the exiled card. You may cast the copy without paying its mana cost. X is the converted mana cost of the exiled card.
|
||||
SVar:X:Remembered$CardManaCost
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.IsRemembered+ExiledWithSource | Origin$ Exile | Destination$ Any | Execute$ ForgetCard | Static$ True
|
||||
SVar:ForgetCard:DB$ Cleanup | ForgetDefined$ TriggeredCard
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
#Amount$ All | CopyOnce$ True for Strionic Resonator
|
||||
SVar:TrigExile:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | ChangeType$ Instant | ChangeNum$ 1
|
||||
A:AB$ Play | Cost$ X T | Valid$ Card.ExiledWithSource | ValidZone$ Exile | Amount$ All | CopyOnce$ True | WithoutManaCost$ True | Optional$ True | CopyCard$ True | SpellDescription$ Copy the exiled card. You may cast the copy without paying its mana cost. X is the converted mana cost of the exiled card.
|
||||
SVar:X:ExiledWith$CardManaCost
|
||||
AI:RemoveDeck:All
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/elite_arcanist.jpg
|
||||
Oracle:When Elite Arcanist enters the battlefield, you may exile an instant card from your hand.\n{X}, {T}: Copy the exiled card. You may cast the copy without paying its mana cost. X is the converted mana cost of the exiled card.
|
||||
|
||||
@@ -2,11 +2,6 @@ Name:Endless Sands
|
||||
ManaCost:no cost
|
||||
Types:Land Desert
|
||||
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
|
||||
A:AB$ ChangeZone | Cost$ 2 T | ValidTgts$ Creature.YouCtrl | Origin$ Battlefield | Destination$ Exile | TgtPrompt$ Select target creature you control | RememberTargets$ True | SpellDescription$ Exile target creature you control.
|
||||
A:AB$ ChangeZoneAll | Cost$ 4 T Sac<1/CARDNAME> | ChangeType$ Card.Creature+IsRemembered+ExiledWithSource | Origin$ Exile | Destination$ Battlefield | SubAbility$ DBCleanup | SpellDescription$ Return each creature card exiled with CARDNAME to the battlefield under its owner's control.
|
||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
|
||||
SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup
|
||||
SVar:DBCleanup:DB$Cleanup | ClearRemembered$ True
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/endless_sands.jpg
|
||||
Oracle:{T}: Add {C}.\n{2}, {T}: Exile target creature you control.\n{4}, {T}, Sacrifice Endless Sands: Return each creature card exiled with Endless Sands to the battlefield under its owner's control.
|
||||
A:AB$ ChangeZone | Cost$ 2 T | ValidTgts$ Creature.YouCtrl | Origin$ Battlefield | Destination$ Exile | TgtPrompt$ Select target creature you control | SpellDescription$ Exile target creature you control.
|
||||
A:AB$ ChangeZone | Cost$ 4 T Sac<1/CARDNAME> | Defined$ ExiledWith | Origin$ Exile | Destination$ Battlefield | SpellDescription$ Return each creature card exiled with CARDNAME to the battlefield under its owner's control.
|
||||
Oracle:{T}: Add {C}.\n{2}, {T}: Exile target creature you control.\n{4}, {T}, Sacrifice Endless Sands: Return each creature card exiled with Endless Sands to the battlefield under its owner's control.
|
||||
|
||||
@@ -2,11 +2,6 @@ Name:Exclusion Ritual
|
||||
ManaCost:4 W W
|
||||
Types:Enchantment
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ TrigExile | TriggerDescription$ Imprint — When CARDNAME enters the battlefield, exile target nonland permanent.
|
||||
SVar:TrigExile:DB$ ChangeZone | Imprint$ True | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | Origin$ Battlefield | Destination$ Exile
|
||||
S:Mode$ CantBeCast | ValidCard$ Card.sharesNameWith Imprinted | Description$ Players can't cast spells with the same name as the exiled card.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | ValidCard$ Card.Self | Destination$ Any | Execute$ DBCleanup | Static$ True
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.IsImprinted+ExiledWithSource | Origin$ Exile | Execute$ DBForget | Static$ True
|
||||
SVar:DBForget:DB$ Pump | ForgetImprinted$ TriggeredCard
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearImprinted$ True
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/exclusion_ritual.jpg
|
||||
Oracle:Imprint — When Exclusion Ritual enters the battlefield, exile target nonland permanent.\nPlayers can't cast spells with the same name as the exiled card.
|
||||
SVar:TrigExile:DB$ ChangeZone | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | Origin$ Battlefield | Destination$ Exile
|
||||
S:Mode$ CantBeCast | ValidCard$ Card.sharesNameWith ExiledWith | Description$ Players can't cast spells with the same name as the exiled card.
|
||||
Oracle:Imprint — When Exclusion Ritual enters the battlefield, exile target nonland permanent.\nPlayers can't cast spells with the same name as the exiled card.
|
||||
|
||||
@@ -3,11 +3,8 @@ ManaCost:2 B B
|
||||
Types:Creature Nightmare Horror
|
||||
PT:2/3
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, exile target creature.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME leaves the battlefield, return the exiled card to the battlefield under its owner's control.
|
||||
SVar:TrigExile:DB$ChangeZone | TargetMin$ 1 | IsCurse$ True | ValidTgts$ Creature.Other | TgtPrompt$ Choose target creature other than Faceless Butcher. | RememberTargets$ True | ForgetOtherTargets$ True | Origin$ Battlefield | Destination$ Exile
|
||||
SVar:TrigReturn:DB$ChangeZoneAll | ChangeType$ Card.IsRemembered+ExiledWithSource | Origin$ Exile | Destination$ Battlefield | SubAbility$ DBCleanup
|
||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
|
||||
SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When CARDNAME leaves the battlefield, return the exiled card to the battlefield under its owner's control.
|
||||
SVar:TrigExile:DB$ ChangeZone | IsCurse$ True | ValidTgts$ Creature.Other | TgtPrompt$ Choose target creature other than CARDNAME. | Origin$ Battlefield | Destination$ Exile
|
||||
SVar:TrigReturn:DB$ ChangeZone | Defined$ ExiledWith | Origin$ Exile | Destination$ Battlefield
|
||||
SVar:PlayMain1:TRUE
|
||||
Oracle:When Faceless Butcher enters the battlefield, exile target creature other than Faceless Butcher.\nWhen Faceless Butcher leaves the battlefield, return the exiled card to the battlefield under its owner's control.
|
||||
|
||||
@@ -3,10 +3,10 @@ ManaCost:2 B
|
||||
Types:Creature Nightmare Horror
|
||||
PT:2/1
|
||||
K:Shadow
|
||||
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, exile another target creature with shadow.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME leaves the battlefield, return the exiled card to the battlefield under its owner's control.
|
||||
SVar:TrigExile:DB$ChangeZone | TargetMin$ 1 | IsCurse$ True | ValidTgts$ Creature.withShadow+Other | TgtPrompt$ Choose target creature with shadow other than Faceless Devourer. | RememberTargets$ True | ForgetOtherTargets$ True | Origin$ Battlefield | Destination$ Exile
|
||||
SVar:TrigReturn:DB$ChangeZone | Defined$ Remembered | Origin$ Exile | Destination$ Battlefield
|
||||
SVar:TrigExile:DB$ ChangeZone | TargetMin$ 1 | IsCurse$ True | ValidTgts$ Creature.withShadow+Other | TgtPrompt$ Choose target creature with shadow other than Faceless Devourer. | Origin$ Battlefield | Destination$ Exile
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When CARDNAME leaves the battlefield, return the exiled card to the battlefield under its owner's control.
|
||||
SVar:TrigReturn:DB$ ChangeZone | Defined$ ExiledWith | Origin$ Exile | Destination$ Battlefield
|
||||
SVar:PlayMain1:TRUE
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/faceless_devourer.jpg
|
||||
Oracle:Shadow (This creature can block or be blocked by only creatures with shadow.)\nWhen Faceless Devourer enters the battlefield, exile another target creature with shadow.\nWhen Faceless Devourer leaves the battlefield, return the exiled card to the battlefield under its owner's control.
|
||||
|
||||
@@ -3,9 +3,8 @@ ManaCost:1 W W
|
||||
Types:Creature Human Cleric
|
||||
PT:1/3
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may exile another target creature.
|
||||
SVar:TrigExile:DB$ChangeZone | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | ForgetOtherRemembered$ True | ValidTgts$ Creature.Other | TgtPrompt$ Select target creature
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME leaves the battlefield, return the exiled card to the battlefield under its owner's control.
|
||||
SVar:TrigReturn:DB$ChangeZone | Origin$ Exile | Destination$ Battlefield | Defined$ DirectRemembered
|
||||
SVar:TrigExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Creature.Other | TgtPrompt$ Select target creature
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When CARDNAME leaves the battlefield, return the exiled card to the battlefield under its owner's control.
|
||||
SVar:TrigReturn:DB$ ChangeZone | Defined$ ExiledWith | Origin$ Exile | Destination$ Battlefield
|
||||
SVar:PlayMain1:TRUE
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/fiend_hunter.jpg
|
||||
Oracle:When Fiend Hunter enters the battlefield, you may exile another target creature.\nWhen Fiend Hunter leaves the battlefield, return the exiled card to the battlefield under its owner's control.
|
||||
|
||||
@@ -6,12 +6,7 @@ T:Mode$ Blocks | ValidCard$ Card.EquippedBy | ValidBlocked$ Creature | Execute$
|
||||
T:Mode$ AttackerBlocked | ValidCard$ Card.EquippedBy | ValidBlocker$ Creature | Execute$ TrigChooseBlockers | OptionalDecider$ You | Secondary$ True | TriggerDescription$ Whenever equipped creature blocks or becomes blocked by one or more creatures, you may exile one of those creatures.
|
||||
SVar:TrigChooseAttackers:DB$ ChooseCard | DefinedCards$ TriggeredAttackers | SubAbility$ DBExile
|
||||
SVar:TrigChooseBlockers:DB$ ChooseCard | DefinedCards$ TriggeredBlockers | SubAbility$ DBExile
|
||||
SVar:DBExile:DB$ ChangeZone | Defined$ ChosenCard | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True
|
||||
S:Mode$ CantBeCast | ValidCard$ Card.nonLand+sharesNameWith Remembered.ExiledWithSource | Caster$ Opponent | Description$ Your opponents can't cast spells with the same name as a card exiled with CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
|
||||
SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Battlefield | Destination$ Any | Execute$ DBCleanup | Static$ True | Secondary$ True | TriggerDescription$ Forget all remembered cards.
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:DBExile:DB$ ChangeZone | Defined$ ChosenCard | Origin$ Battlefield | Destination$ Exile
|
||||
S:Mode$ CantBeCast | ValidCard$ Card.nonLand+sharesNameWith ExiledWith | Caster$ Opponent | Description$ Your opponents can't cast spells with the same name as a card exiled with CARDNAME.
|
||||
K:Equip:3
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/godsend.jpg
|
||||
Oracle:Equipped creature gets +3/+3.\nWhenever equipped creature blocks or becomes blocked by one or more creatures, you may exile one of those creatures.\nYour opponents can't cast spells with the same name as a card exiled with Godsend.\nEquip {3}
|
||||
|
||||
@@ -3,8 +3,7 @@ ManaCost:2 B
|
||||
Types:Creature Nightmare Horror
|
||||
PT:2/2
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, exile up to two target cards from a single graveyard.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME leaves the battlefield, return the exiled cards to their owner's graveyard.
|
||||
SVar:TrigExile:DB$ChangeZone | TargetMin$ 0 | TargetMax$ 2 | TargetsFromSingleZone$ True | Origin$ Graveyard | Destination$ Exile | ValidTgts$ Card | RememberTargets$ True | ForgetOtherTargets$ True
|
||||
SVar:TrigReturn:DB$ChangeZone | Defined$ Remembered | Origin$ Exile | Destination$ Graveyard
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/gravegouger.jpg
|
||||
SVar:TrigExile:DB$ ChangeZone | TargetMin$ 0 | TargetMax$ 2 | TargetsFromSingleZone$ True | Origin$ Graveyard | Destination$ Exile | ValidTgts$ Card
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When CARDNAME leaves the battlefield, return the exiled cards to their owner's graveyard.
|
||||
SVar:TrigReturn:DB$ ChangeZone | Defined$ ExiledWith | Origin$ Exile | Destination$ Graveyard
|
||||
Oracle:When Gravegouger enters the battlefield, exile up to two target cards from a single graveyard.\nWhen Gravegouger leaves the battlefield, return the exiled cards to their owner's graveyard.
|
||||
|
||||
@@ -3,14 +3,10 @@ ManaCost:U U
|
||||
Types:Creature Merfolk Rogue
|
||||
PT:2/2
|
||||
T:Mode$ Taps | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ Whenever CARDNAME becomes tapped, exile the top three cards of target opponent's library face down.
|
||||
SVar:TrigExile:DB$ Dig | ValidTgts$ Opponent | DigNum$ 3 | ChangeNum$ All | DestinationZone$ Exile | ExileFaceDown$ True | RememberChanged$ True
|
||||
S:Mode$ Continuous | Affected$ Card.IsRemembered+ExiledWithSource | AffectedZone$ Exile | MayLookAt$ You | Description$ You may look at cards exiled with CARDNAME.
|
||||
A:AB$ SetState | Cost$ U Sac<1/CARDNAME> | Defined$ Remembered | Mode$ TurnFace | SubAbility$ DBCounter | SpellDescription$ Turn all cards exiled with CARDNAME face up. Counter all spells with those names.
|
||||
SVar:DBCounter:DB$ Counter | AllType$ Spell | AllValid$ Card.sharesNameWith Remembered.ExiledWithSource | SubAbility$ DBCleanup
|
||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
|
||||
SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:TrigExile:DB$ Dig | ValidTgts$ Opponent | DigNum$ 3 | ChangeNum$ All | DestinationZone$ Exile | ExileFaceDown$ True
|
||||
S:Mode$ Continuous | Affected$ Card.ExiledWithSource | AffectedZone$ Exile | MayLookAt$ You | Description$ You may look at cards exiled with CARDNAME.
|
||||
A:AB$ SetState | Cost$ U Sac<1/CARDNAME> | Defined$ ExiledWith | Mode$ TurnFace | SubAbility$ DBCounter | SpellDescription$ Turn all cards exiled with CARDNAME face up. Counter all spells with those names.
|
||||
SVar:DBCounter:DB$ Counter | AllType$ Spell | AllValid$ Card.sharesNameWith ExiledWith | SubAbility$ DBCleanup
|
||||
AI:RemoveDeck:All
|
||||
AI:RemoveDeck:Random
|
||||
Oracle:Whenever Grimoire Thief becomes tapped, exile the top three cards of target opponent's library face down.\nYou may look at cards exiled with Grimoire Thief.\n{U}, Sacrifice Grimoire Thief: Turn all cards exiled with Grimoire Thief face up. Counter all spells with those names.
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
Name:Gustha's Scepter
|
||||
ManaCost:0
|
||||
Types:Artifact
|
||||
A:AB$ ChangeZone | Cost$ T | ChangeType$ Card | ChangeNum$ 1 | Origin$ Hand | Destination$ Exile | ExileFaceDown$ True | RememberChanged$ True | Mandatory$ True | SubAbility$ DBEffect | SpellDescription$ Exile a card from your hand face down. You may look at it for as long as it remains exiled.
|
||||
SVar:DBEffect:DB$ Effect | RememberObjects$ Remembered | StaticAbilities$ STLook | Duration$ Permanent | ForgetOnMoved$ Exile | SubAbility$ DBCleanup
|
||||
SVar:STLook:Mode$ Continuous | MayLookAt$ You | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may look at it for as long as it remains exiled.
|
||||
A:AB$ ChooseCard | Cost$ T | Defined$ You | Amount$ 1 | Mandatory$ True | AILogic$ AtLeast1 | ChoiceTitle$ Choose a card you own to put into your hand | Choices$ Card.IsRemembered+YouOwn+ExiledWithSource | ChoiceZone$ Exile | SubAbility$ MoveChosen | SpellDescription$ Return a card you own exiled with CARDNAME to your hand.
|
||||
SVar:MoveChosen:DB$ ChangeZone | Origin$ Exile | Destination$ Hand | Defined$ ChosenCard
|
||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
|
||||
SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ DBChangeZoneAll | TriggerDescription$ When you lose control of CARDNAME, put all cards exiled with CARDNAME into their owner's graveyard.
|
||||
T:Mode$ ChangesController | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ DBChangeZoneAll | Secondary$ True | TriggerDescription$ When you lose control of CARDNAME, put all cards exiled with CARDNAME into their owner's graveyard.
|
||||
SVar:DBChangeZoneAll:DB$ ChangeZoneAll | ChangeType$ Card.IsRemembered | Origin$ Exile | Destination$ Graveyard | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
A:AB$ ChangeZone | Cost$ T | ChangeType$ Card | ChangeNum$ 1 | Origin$ Hand | Destination$ Exile | ExileFaceDown$ True | ExilePeek$ True | Mandatory$ True | SpellDescription$ Exile a card from your hand face down. You may look at it for as long as it remains exiled.
|
||||
A:AB$ ChangeZone | Cost$ T | Hidden$ True | Origin$ Exile | Destination$ Hand | ChangeType$ Creature.ExiledWithSource+YouOwn | ChangeNum$ 1 | Mandatory$ True | StackDescription$ SpellDescription | SpellDescription$ Return a card you own exiled with CARDNAME to your hand.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ DBChangeZone | TriggerDescription$ When you lose control of CARDNAME, put all cards exiled with CARDNAME into their owner's graveyard.
|
||||
T:Mode$ ChangesController | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ DBChangeZone | Secondary$ True | TriggerDescription$ When you lose control of CARDNAME, put all cards exiled with CARDNAME into their owner's graveyard.
|
||||
SVar:DBChangeZone:DB$ ChangeZone | Defined$ ExiledWith | Origin$ Exile | Destination$ Graveyard
|
||||
AI:RemoveDeck:All
|
||||
Oracle:{T}: Exile a card from your hand face down. You may look at it for as long as it remains exiled.\n{T}: Return a card you own exiled with Gustha's Scepter to your hand.\nWhen you lose control of Gustha's Scepter, put all cards exiled with Gustha's Scepter into their owner's graveyard.
|
||||
|
||||
@@ -2,12 +2,7 @@ Name:Hedonist's Trove
|
||||
ManaCost:5 B B
|
||||
Types:Enchantment
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, exile all cards from target opponent's graveyard.
|
||||
SVar:TrigExile:DB$ ChangeZoneAll | ValidTgts$ Opponent | TgtPrompt$ Select target Opponent | Origin$ Graveyard | Destination$ Exile | ChangeType$ Card | IsCurse$ True | RememberChanged$ True
|
||||
S:Mode$ Continuous | MayPlay$ True | Affected$ Land.IsRemembered+ExiledWithSource | AffectedZone$ Exile | Description$ You may play lands from among cards exiled with CARDNAME.
|
||||
S:Mode$ Continuous | MayPlay$ True | MayPlayLimit$ 1 | Affected$ Card.nonLand+IsRemembered+ExiledWithSource | AffectedZone$ Exile | Description$ You may play cards exiled with CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
|
||||
SVar:DBForget:DB$ Pump | Defined$ TriggeredCard | ForgetObjects$ TriggeredCard
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/hedonists_trove.jpg
|
||||
SVar:TrigExile:DB$ ChangeZoneAll | ValidTgts$ Opponent | TgtPrompt$ Select target Opponent | Origin$ Graveyard | Destination$ Exile | ChangeType$ Card | IsCurse$ True
|
||||
S:Mode$ Continuous | MayPlay$ True | Affected$ Land.ExiledWithSource | AffectedZone$ Exile | Description$ You may play lands from among cards exiled with CARDNAME.
|
||||
S:Mode$ Continuous | MayPlay$ True | MayPlayLimit$ 1 | Affected$ Card.nonLand+ExiledWithSource | AffectedZone$ Exile | Description$ You may cast spells from among cards exiled with CARDNAME. You can't cast more than one spell this way each turn.
|
||||
Oracle:When Hedonist's Trove enters the battlefield, exile all cards from target opponent's graveyard.\nYou may play lands from among cards exiled with Hedonist's Trove.\nYou may cast spells from among cards exiled with Hedonist's Trove. You can't cast more than one spell this way each turn.
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
Name:Helvault
|
||||
ManaCost:3
|
||||
Types:Legendary Artifact
|
||||
A:AB$ ChangeZone | Cost$ 1 T | ValidTgts$ Creature.YouCtrl | Origin$ Battlefield | Destination$ Exile | TgtPrompt$ Select target creature you control | RememberTargets$ True | SpellDescription$ Exile target creature you control.
|
||||
A:AB$ ChangeZone | Cost$ 7 T | ValidTgts$ Creature.YouDontCtrl | Origin$ Battlefield | Destination$ Exile | TgtPrompt$ Select target creature you don't control | RememberTargets$ True | IsCurse$ True | SpellDescription$ Exile target creature you don't control.
|
||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
|
||||
SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard
|
||||
A:AB$ ChangeZone | Cost$ 1 T | ValidTgts$ Creature.YouCtrl | Origin$ Battlefield | Destination$ Exile | TgtPrompt$ Select target creature you control | SpellDescription$ Exile target creature you control.
|
||||
A:AB$ ChangeZone | Cost$ 7 T | ValidTgts$ Creature.YouDontCtrl | Origin$ Battlefield | Destination$ Exile | TgtPrompt$ Select target creature you don't control | IsCurse$ True | SpellDescription$ Exile target creature you don't control.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME is put into a graveyard from the battlefield, return all cards exiled with it to the battlefield under their owners' control.
|
||||
SVar:TrigReturn:DB$ ChangeZoneAll | ChangeType$ Card.IsRemembered+ExiledWithSource | Origin$ Exile | Destination$ Battlefield | Destination$ Battlefield | SubAbility$ DBCleanup
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ExcludedDestinations$ Graveyard | ValidCard$ Card.Self | Execute$ DBCleanup | Static$ True
|
||||
SVar:DBCleanup:DB$Cleanup | ClearRemembered$ True
|
||||
SVar:TrigReturn:DB$ ChangeZone | Defined$ ExiledWith | Origin$ Exile | Destination$ Battlefield | Destination$ Battlefield
|
||||
AI:RemoveDeck:All
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/helvault.jpg
|
||||
Oracle:{1}, {T}: Exile target creature you control.\n{7}, {T}: Exile target creature you don't control.\nWhen Helvault is put into a graveyard from the battlefield, return all cards exiled with it to the battlefield under their owners' control.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user