mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 10:48:00 +00:00
Merge branch 'master' of https://git.cardforge.org/core-developers/forge
This commit is contained in:
@@ -102,6 +102,7 @@ public class DeckRecognizer {
|
||||
// Pattern.compile("(.*)[^A-Za-wyz]*\\s+([\\d]{1,2})");
|
||||
private static final Pattern SEARCH_NUMBERS_IN_FRONT = Pattern.compile("([\\d]{1,2})[^A-Za-wyz]*\\s+(.*)");
|
||||
//private static final Pattern READ_SEPARATED_EDITION = Pattern.compile("[[\\(\\{]([a-zA-Z0-9]){1,3})[]*\\s+(.*)");
|
||||
private static final Pattern SEARCH_SINGLE_SLASH = Pattern.compile("(?<=[^/])\\s*/\\s*(?=[^/])");
|
||||
|
||||
private final SetPreference useLastSet;
|
||||
private final ICardDatabase db;
|
||||
@@ -125,7 +126,10 @@ public class DeckRecognizer {
|
||||
return new Token(TokenType.Comment, 0, rawLine);
|
||||
}
|
||||
final char smartQuote = (char) 8217;
|
||||
final String line = rawLine.trim().replace(smartQuote, '\'');
|
||||
String line = rawLine.trim().replace(smartQuote, '\'');
|
||||
|
||||
// Some websites export split card names with a single slash. Replace with double slash.
|
||||
line = SEARCH_SINGLE_SLASH.matcher(line).replaceFirst(" // ");
|
||||
|
||||
Token result = null;
|
||||
final Matcher foundNumbersInFront = DeckRecognizer.SEARCH_NUMBERS_IN_FRONT.matcher(line);
|
||||
|
||||
@@ -29,6 +29,7 @@ import forge.game.ability.effects.AttachEffect;
|
||||
import forge.game.card.*;
|
||||
import forge.game.event.*;
|
||||
import forge.game.keyword.KeywordInterface;
|
||||
import forge.game.keyword.KeywordsChange;
|
||||
import forge.game.player.GameLossReason;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.replacement.ReplacementEffect;
|
||||
@@ -292,6 +293,33 @@ public class GameAction {
|
||||
copied.getOwner().addInboundToken(copied);
|
||||
}
|
||||
|
||||
if (toBattlefield) {
|
||||
// HACK for making the RIOT enchantment look into the Future
|
||||
// need to check the Keywords what it would have on the Battlefield
|
||||
Card riotLKI = CardUtil.getLKICopy(copied);
|
||||
riotLKI.setLastKnownZone(zoneTo);
|
||||
CardCollection preList = new CardCollection(riotLKI);
|
||||
checkStaticAbilities(false, Sets.newHashSet(riotLKI), preList);
|
||||
|
||||
List<Long> changedTimeStamps = Lists.newArrayList();
|
||||
for(Map.Entry<Long, KeywordsChange> e : riotLKI.getChangedCardKeywords().entrySet()) {
|
||||
if (!copied.hasChangedCardKeywords(e.getKey())) {
|
||||
KeywordsChange o = e.getValue();
|
||||
o.setHostCard(copied);
|
||||
for (KeywordInterface k : o.getKeywords()) {
|
||||
for (ReplacementEffect re : k.getReplacements()) {
|
||||
// this param need to be set, otherwise in ReplaceMoved it fails
|
||||
re.getMapParams().put("BypassEtbCheck", "True");
|
||||
}
|
||||
}
|
||||
copied.addChangedCardKeywordsInternal(o, e.getKey());
|
||||
changedTimeStamps.add(e.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
checkStaticAbilities(false);
|
||||
}
|
||||
|
||||
Map<String, Object> repParams = Maps.newHashMap();
|
||||
repParams.put("Event", "Moved");
|
||||
repParams.put("Affected", copied);
|
||||
|
||||
@@ -1465,7 +1465,8 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (keyword.startsWith("CantBeCounteredBy")) {
|
||||
if (keyword.startsWith("CantBeCounteredBy") || keyword.startsWith("Panharmonicon")
|
||||
|| keyword.startsWith("Dieharmonicon")) {
|
||||
final String[] p = keyword.split(":");
|
||||
sbLong.append(p[2]).append("\r\n");
|
||||
} else if (keyword.startsWith("etbCounter")) {
|
||||
@@ -3404,6 +3405,15 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
return change;
|
||||
}
|
||||
|
||||
public final boolean hasChangedCardKeywords(final long timestamp) {
|
||||
return changedCardKeywords.containsKey(timestamp);
|
||||
}
|
||||
|
||||
public final void addChangedCardKeywordsInternal(final KeywordsChange change, final long timestamp) {
|
||||
changedCardKeywords.put(timestamp, change);
|
||||
updateKeywordsCache(currentState);
|
||||
}
|
||||
|
||||
// Hidden keywords will be left out
|
||||
public final Collection<KeywordInterface> getUnhiddenKeywords() {
|
||||
return getUnhiddenKeywords(currentState);
|
||||
@@ -5731,7 +5741,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
public void setChangedCardKeywords(Map<Long, KeywordsChange> changedCardKeywords) {
|
||||
this.changedCardKeywords.clear();
|
||||
for (Entry<Long, KeywordsChange> entry : changedCardKeywords.entrySet()) {
|
||||
this.changedCardKeywords.put(entry.getKey(), entry.getValue());
|
||||
this.changedCardKeywords.put(entry.getKey(), entry.getValue().copy(this, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Table;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.trigger.TriggerType;
|
||||
import forge.game.zone.ZoneType;
|
||||
|
||||
@@ -45,4 +46,39 @@ public class CardZoneTable extends ForwardingTable<ZoneType, ZoneType, CardColle
|
||||
game.getTriggerHandler().runTrigger(TriggerType.ChangesZoneAll, runParams, false);
|
||||
}
|
||||
}
|
||||
|
||||
public CardCollection filterCards(Iterable<ZoneType> origin, ZoneType destination, String valid, Card host, SpellAbility sa) {
|
||||
CardCollection allCards = new CardCollection();
|
||||
if (destination != null) {
|
||||
if (!containsColumn(destination)) {
|
||||
return allCards;
|
||||
}
|
||||
}
|
||||
if (origin != null) {
|
||||
for (ZoneType z : origin) {
|
||||
if (containsRow(z)) {
|
||||
if (destination != null) {
|
||||
allCards.addAll(row(z).get(destination));
|
||||
} else {
|
||||
for (CardCollection c : row(z).values()) {
|
||||
allCards.addAll(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (destination != null) {
|
||||
for (CardCollection c : column(destination).values()) {
|
||||
allCards.addAll(c);
|
||||
}
|
||||
} else {
|
||||
for (CardCollection c : values()) {
|
||||
allCards.addAll(c);
|
||||
}
|
||||
}
|
||||
|
||||
if (valid != null) {
|
||||
allCards = CardLists.getValidCards(allCards, valid.split(","), host.getController(), host, sa);
|
||||
}
|
||||
return allCards;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import java.util.Iterator;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.MultimapBuilder;
|
||||
|
||||
import forge.game.card.Card;
|
||||
|
||||
public class KeywordCollection implements Iterable<String>, Serializable {
|
||||
private static final long serialVersionUID = -2882986558147844702L;
|
||||
|
||||
@@ -151,6 +153,12 @@ public class KeywordCollection implements Iterable<String>, Serializable {
|
||||
return map.get(keyword);
|
||||
}
|
||||
|
||||
public void setHostCard(final Card host) {
|
||||
for (KeywordInterface k : map.values()) {
|
||||
k.setHostCard(host);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<String> iterator() {
|
||||
return new Iterator<String>() {
|
||||
|
||||
@@ -233,7 +233,7 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
|
||||
|
||||
return result;
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException("KeywordInstance : clone() error, " + ex);
|
||||
throw new RuntimeException("KeywordInstance : clone() error", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,4 +252,26 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
|
||||
public boolean redundant(Collection<KeywordInterface> list) {
|
||||
return !list.isEmpty() && keyword.isMultipleRedundant;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.game.keyword.KeywordInterface#setHostCard(forge.game.card.Card)
|
||||
*/
|
||||
@Override
|
||||
public void setHostCard(Card host) {
|
||||
for (SpellAbility sa : this.abilities) {
|
||||
sa.setHostCard(host);
|
||||
}
|
||||
|
||||
for (Trigger tr : this.triggers) {
|
||||
tr.setHostCard(host);
|
||||
}
|
||||
|
||||
for (ReplacementEffect re : this.replacements) {
|
||||
re.setHostCard(host);
|
||||
}
|
||||
|
||||
for (StaticAbility sa : this.staticAbilities) {
|
||||
sa.setHostCard(host);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ public interface KeywordInterface extends Cloneable {
|
||||
public void addSpellAbility(final SpellAbility s);
|
||||
public void addStaticAbility(final StaticAbility st);
|
||||
|
||||
public void setHostCard(final Card host);
|
||||
|
||||
/**
|
||||
* @return the triggers
|
||||
|
||||
@@ -30,12 +30,11 @@ import forge.game.card.Card;
|
||||
* </p>
|
||||
*
|
||||
* @author Forge
|
||||
* @version $Id: KeywordsChange.java 27095 2014-08-17 07:32:24Z elcnesh $
|
||||
*/
|
||||
public class KeywordsChange {
|
||||
private final KeywordCollection keywords = new KeywordCollection();
|
||||
private final List<KeywordInterface> removeKeywordInterfaces = Lists.newArrayList();
|
||||
private final List<String> removeKeywords = Lists.newArrayList();
|
||||
public class KeywordsChange implements Cloneable {
|
||||
private KeywordCollection keywords = new KeywordCollection();
|
||||
private List<KeywordInterface> removeKeywordInterfaces = Lists.newArrayList();
|
||||
private List<String> removeKeywords = Lists.newArrayList();
|
||||
private boolean removeAllKeywords;
|
||||
private boolean removeIntrinsicKeywords;
|
||||
|
||||
@@ -172,4 +171,49 @@ public class KeywordsChange {
|
||||
removeIntrinsicKeywords = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void setHostCard(final Card host) {
|
||||
keywords.setHostCard(host);
|
||||
for (KeywordInterface k : removeKeywordInterfaces) {
|
||||
k.setHostCard(host);
|
||||
}
|
||||
}
|
||||
|
||||
public KeywordsChange copy(final Card host, final boolean lki) {
|
||||
try {
|
||||
KeywordsChange result = (KeywordsChange)super.clone();
|
||||
|
||||
result.keywords = new KeywordCollection();
|
||||
for (KeywordInterface ki : this.keywords.getValues()) {
|
||||
result.keywords.insert(ki.copy(host, lki));
|
||||
}
|
||||
|
||||
result.removeKeywords = Lists.newArrayList(removeKeywords);
|
||||
|
||||
result.removeKeywordInterfaces = Lists.newArrayList();
|
||||
for (KeywordInterface ki : this.removeKeywordInterfaces) {
|
||||
removeKeywordInterfaces.add(ki.copy(host, lki));
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException("KeywordsChange : clone() error", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("<+");
|
||||
sb.append(this.keywords);
|
||||
sb.append("|-");
|
||||
sb.append(this.removeKeywordInterfaces);
|
||||
sb.append("|-");
|
||||
sb.append(this.removeKeywords);
|
||||
sb.append(">");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ public class ReplaceMoved extends ReplacementEffect {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (zt.equals(ZoneType.Battlefield) && getHostCard().equals(affected)) {
|
||||
if (zt.equals(ZoneType.Battlefield) && getHostCard().equals(affected) && !hasParam("BypassEtbCheck")) {
|
||||
// would be an etb replacement effect that enters the battlefield
|
||||
Card lki = CardUtil.getLKICopy(affected);
|
||||
lki.setLastKnownZone(lki.getController().getZone(zt));
|
||||
|
||||
@@ -42,48 +42,19 @@ public class TriggerChangesZoneAll extends Trigger {
|
||||
}
|
||||
|
||||
private CardCollection filterCards(CardZoneTable table) {
|
||||
CardCollection allCards = new CardCollection();
|
||||
ZoneType destination = null;
|
||||
List<ZoneType> origin = null;
|
||||
|
||||
if (hasParam("Destination")) {
|
||||
if (!getParam("Destination").equals("Any")) {
|
||||
destination = ZoneType.valueOf(getParam("Destination"));
|
||||
if (!table.containsColumn(destination)) {
|
||||
return allCards;
|
||||
}
|
||||
}
|
||||
if (hasParam("Destination") && !getParam("Destination").equals("Any")) {
|
||||
destination = ZoneType.valueOf(getParam("Destination"));
|
||||
}
|
||||
|
||||
if (hasParam("Origin") && !getParam("Origin").equals("Any")) {
|
||||
if (getParam("Origin") == null) {
|
||||
return allCards;
|
||||
}
|
||||
final List<ZoneType> origin = ZoneType.listValueOf(getParam("Origin"));
|
||||
for (ZoneType z : origin) {
|
||||
if (table.containsRow(z)) {
|
||||
if (destination != null) {
|
||||
allCards.addAll(table.row(z).get(destination));
|
||||
} else {
|
||||
for (CardCollection c : table.row(z).values()) {
|
||||
allCards.addAll(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (destination != null) {
|
||||
for (CardCollection c : table.column(destination).values()) {
|
||||
allCards.addAll(c);
|
||||
}
|
||||
} else {
|
||||
for (CardCollection c : table.values()) {
|
||||
allCards.addAll(c);
|
||||
}
|
||||
origin = ZoneType.listValueOf(getParam("Origin"));
|
||||
}
|
||||
|
||||
if (hasParam("ValidCards")) {
|
||||
allCards = CardLists.getValidCards(allCards, getParam("ValidCards").split(","),
|
||||
getHostCard().getController(), getHostCard(), null);
|
||||
}
|
||||
return allCards;
|
||||
final String valid = this.getParamOrDefault("ValidCards", null);
|
||||
|
||||
return table.filterCards(origin, destination, valid, getHostCard(), null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,10 @@ import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.ability.effects.CharmEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.card.CardUtil;
|
||||
import forge.game.card.CardZoneTable;
|
||||
import forge.game.keyword.KeywordInterface;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.Ability;
|
||||
@@ -42,6 +45,7 @@ import io.sentry.event.BreadcrumbBuilder;
|
||||
import java.util.*;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
@@ -376,11 +380,7 @@ public class TriggerHandler {
|
||||
// Static triggers
|
||||
for (final Trigger t : Lists.newArrayList(activeTriggers)) {
|
||||
if (t.isStatic() && canRunTrigger(t, mode, runParams)) {
|
||||
int x = 1 + handlePanharmonicon(t, runParams);
|
||||
|
||||
for (int i = 0; i < x; ++i) {
|
||||
runSingleTrigger(t, runParams);
|
||||
}
|
||||
runSingleTrigger(t, runParams);
|
||||
|
||||
checkStatics = true;
|
||||
}
|
||||
@@ -448,7 +448,7 @@ public class TriggerHandler {
|
||||
}
|
||||
}
|
||||
|
||||
int x = 1 + handlePanharmonicon(t, runParams);;
|
||||
int x = 1 + handlePanharmonicon(t, runParams, player);
|
||||
|
||||
for (int i = 0; i < x; ++i) {
|
||||
runSingleTrigger(t, runParams);
|
||||
@@ -692,46 +692,81 @@ public class TriggerHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private int handlePanharmonicon(final Trigger t, final Map<String, Object> runParams) {
|
||||
// Need to get the last info from the trigger host
|
||||
final Card host = game.getChangeZoneLKIInfo(t.getHostCard());
|
||||
final Player p = host.getController();
|
||||
private int handlePanharmonicon(final Trigger t, final Map<String, Object> runParams, final Player p) {
|
||||
Card host = t.getHostCard();
|
||||
|
||||
// not a changesZone trigger
|
||||
if (t.getMode() != TriggerType.ChangesZone) {
|
||||
// not a changesZone trigger or changesZoneAll
|
||||
if (t.getMode() != TriggerType.ChangesZone && t.getMode() != TriggerType.ChangesZoneAll) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// leave battlefield trigger, might be dying
|
||||
// only real changeszone look back for this
|
||||
if (t.getMode() == TriggerType.ChangesZone && "Battlefield".equals(t.getParam("Origin"))) {
|
||||
// Need to get the last info from the trigger host
|
||||
host = game.getChangeZoneLKIInfo(host);
|
||||
}
|
||||
|
||||
// not a Permanent you control
|
||||
if (!host.isPermanent() || !host.isInZone(ZoneType.Battlefield)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int n = 0;
|
||||
for (final String kw : p.getKeywords()) {
|
||||
if (kw.startsWith("Panharmonicon")) {
|
||||
// Enter the Battlefield Trigger
|
||||
if (runParams.get("Destination") instanceof String) {
|
||||
final String dest = (String) runParams.get("Destination");
|
||||
if ("Battlefield".equals(dest) && runParams.get("Card") instanceof Card) {
|
||||
final Card card = (Card) runParams.get("Card");
|
||||
final String valid = kw.split(":")[1];
|
||||
if (card.isValid(valid.split(","), p, host, null)) {
|
||||
n++;
|
||||
if (t.getMode() == TriggerType.ChangesZone) {
|
||||
// iterate over all cards
|
||||
final List<Card> lastCards = CardLists.filterControlledBy(p.getGame().getLastStateBattlefield(), p);
|
||||
for (final Card ck : lastCards) {
|
||||
for (final KeywordInterface ki : ck.getKeywords()) {
|
||||
final String kw = ki.getOriginal();
|
||||
if (kw.startsWith("Panharmonicon")) {
|
||||
// Enter the Battlefield Trigger
|
||||
if (runParams.get("Destination") instanceof String) {
|
||||
final String dest = (String) runParams.get("Destination");
|
||||
if ("Battlefield".equals(dest) && runParams.get("Card") instanceof Card) {
|
||||
final Card card = (Card) runParams.get("Card");
|
||||
final String valid = kw.split(":")[1];
|
||||
if (card.isValid(valid.split(","), p, ck, null)) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (kw.startsWith("Dieharmonicon")) {
|
||||
// 700.4. The term dies means “is put into a graveyard from the battlefield.”
|
||||
if (runParams.get("Origin") instanceof String) {
|
||||
final String origin = (String) runParams.get("Origin");
|
||||
if ("Battlefield".equals(origin) && runParams.get("Destination") instanceof String) {
|
||||
final String dest = (String) runParams.get("Destination");
|
||||
if ("Graveyard".equals(dest) && runParams.get("Card") instanceof Card) {
|
||||
final Card card = (Card) runParams.get("Card");
|
||||
final String valid = kw.split(":")[1];
|
||||
if (card.isValid(valid.split(","), p, ck, null)) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (kw.startsWith("Dieharmonicon")) {
|
||||
// 700.4. The term dies means “is put into a graveyard from the battlefield.”
|
||||
if (runParams.get("Origin") instanceof String) {
|
||||
final String origin = (String) runParams.get("Origin");
|
||||
if ("Battlefield".equals(origin) && runParams.get("Destination") instanceof String) {
|
||||
final String dest = (String) runParams.get("Destination");
|
||||
if ("Graveyard".equals(dest) && runParams.get("Card") instanceof Card) {
|
||||
final Card card = (Card) runParams.get("Card");
|
||||
if (card.isCreature()) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
} else if (t.getMode() == TriggerType.ChangesZoneAll) {
|
||||
final CardZoneTable table = (CardZoneTable) runParams.get("Cards");
|
||||
// iterate over all cards
|
||||
for (final Card ck : p.getCardsIn(ZoneType.Battlefield)) {
|
||||
for (final KeywordInterface ki : ck.getKeywords()) {
|
||||
final String kw = ki.getOriginal();
|
||||
if (kw.startsWith("Panharmonicon")) {
|
||||
// currently there is no ChangesZoneAll that would trigger on etb
|
||||
final String valid = kw.split(":")[1];
|
||||
if (!table.filterCards(null, ZoneType.Battlefield, valid, ck, null).isEmpty()) {
|
||||
n++;
|
||||
}
|
||||
} else if (kw.startsWith("Dieharmonicon")) {
|
||||
// 700.4. The term dies means “is put into a graveyard from the battlefield.”
|
||||
final String valid = kw.split(":")[1];
|
||||
if (!table.filterCards(ImmutableList.of(ZoneType.Battlefield), ZoneType.Graveyard,
|
||||
valid, ck, null).isEmpty()) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ public class TriggerWaiting {
|
||||
private Map<String, Object> params;
|
||||
private List<Trigger> triggers = null;
|
||||
|
||||
public TriggerWaiting(TriggerType m, Map<String, Object> p) {
|
||||
public TriggerWaiting(TriggerType m, Map<String, Object> p) {
|
||||
mode = m;
|
||||
params = p;
|
||||
}
|
||||
@@ -26,7 +26,6 @@ public class TriggerWaiting {
|
||||
return params;
|
||||
}
|
||||
|
||||
|
||||
public List<Trigger> getTriggers() {
|
||||
return triggers;
|
||||
}
|
||||
@@ -35,7 +34,7 @@ public class TriggerWaiting {
|
||||
this.triggers = triggers;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public String toString() {
|
||||
return TextUtil.concatWithSpace("Waiting trigger:", mode.toString(),"with", params.toString());
|
||||
}
|
||||
|
||||
@@ -1503,4 +1503,197 @@ public class GameSimulatorTest extends SimulationTestCase {
|
||||
}
|
||||
|
||||
|
||||
public void testRiotEnchantment() {
|
||||
Game game = initAndCreateGame();
|
||||
Player p = game.getPlayers().get(0);
|
||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
|
||||
|
||||
final String goblinName = "Zhur-Taa Goblin";
|
||||
|
||||
addCard("Rhythm of the Wild", p);
|
||||
|
||||
Card goblin = addCardToZone(goblinName, p, ZoneType.Hand);
|
||||
|
||||
addCard("Mountain", p);
|
||||
addCard("Forest", p);
|
||||
|
||||
SpellAbility goblinSA = goblin.getFirstSpellAbility();
|
||||
assertNotNull(goblinSA);
|
||||
|
||||
GameSimulator sim = createSimulator(game, p);
|
||||
int score = sim.simulateSpellAbility(goblinSA).value;
|
||||
assertTrue(score > 0);
|
||||
|
||||
Game simGame = sim.getSimulatedGameState();
|
||||
|
||||
Card simGoblin = findCardWithName(simGame, goblinName);
|
||||
|
||||
assertNotNull(simGoblin);
|
||||
int effects = simGoblin.getCounters(CounterType.P1P1) + simGoblin.getKeywordMagnitude(Keyword.HASTE);
|
||||
assertTrue(effects == 2);
|
||||
}
|
||||
|
||||
public void testTeysaKarlovXathridNecromancer() {
|
||||
// Teysa Karlov and Xathrid Necromancer dying at the same time makes 4 token
|
||||
|
||||
Game game = initAndCreateGame();
|
||||
Player p = game.getPlayers().get(0);
|
||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
|
||||
|
||||
addCard("Teysa Karlov", p);
|
||||
addCard("Xathrid Necromancer", p);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
addCardToZone("Plains", p, ZoneType.Battlefield);
|
||||
}
|
||||
|
||||
Card wrathOfGod = addCardToZone("Wrath of God", p, ZoneType.Hand);
|
||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
||||
|
||||
SpellAbility wrathSA = wrathOfGod.getFirstSpellAbility();
|
||||
assertNotNull(wrathSA);
|
||||
|
||||
GameSimulator sim = createSimulator(game, p);
|
||||
int score = sim.simulateSpellAbility(wrathSA).value;
|
||||
assertTrue(score > 0);
|
||||
Game simGame = sim.getSimulatedGameState();
|
||||
|
||||
int numZombies = countCardsWithName(simGame, "Zombie");
|
||||
assertTrue(numZombies == 4);
|
||||
}
|
||||
|
||||
public void testDoubleTeysaKarlovXathridNecromancer() {
|
||||
// Teysa Karlov dieing because of Legendary rule will make Xathrid Necromancer trigger 3 times
|
||||
|
||||
Game game = initAndCreateGame();
|
||||
Player p = game.getPlayers().get(0);
|
||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
|
||||
|
||||
addCard("Teysa Karlov", p);
|
||||
addCard("Xathrid Necromancer", p);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
addCard("Plains", p);
|
||||
}
|
||||
addCard("Swamp", p);
|
||||
|
||||
Card second = addCardToZone("Teysa Karlov", p, ZoneType.Hand);
|
||||
|
||||
SpellAbility secondSA = second.getFirstSpellAbility();
|
||||
|
||||
GameSimulator sim = createSimulator(game, p);
|
||||
int score = sim.simulateSpellAbility(secondSA).value;
|
||||
assertTrue(score > 0);
|
||||
Game simGame = sim.getSimulatedGameState();
|
||||
|
||||
int numZombies = countCardsWithName(simGame, "Zombie");
|
||||
assertTrue(numZombies == 3);
|
||||
}
|
||||
|
||||
|
||||
public void testTeysaKarlovGitrogMonster() {
|
||||
|
||||
Game game = initAndCreateGame();
|
||||
Player p = game.getPlayers().get(0);
|
||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
|
||||
|
||||
addCard("Teysa Karlov", p);
|
||||
addCard("The Gitrog Monster", p);
|
||||
addCard("Dryad Arbor", p);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
addCard("Plains", p);
|
||||
addCardToZone("Plains", p, ZoneType.Library);
|
||||
}
|
||||
|
||||
Card armageddon = addCardToZone("Armageddon", p, ZoneType.Hand);
|
||||
|
||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
||||
|
||||
SpellAbility armageddonSA = armageddon.getFirstSpellAbility();
|
||||
|
||||
GameSimulator sim = createSimulator(game, p);
|
||||
int score = sim.simulateSpellAbility(armageddonSA).value;
|
||||
assertTrue(score > 0);
|
||||
Game simGame = sim.getSimulatedGameState();
|
||||
|
||||
// Two cards drawn
|
||||
assertTrue(simGame.getPlayers().get(0).getZone(ZoneType.Hand).size() == 2);
|
||||
}
|
||||
|
||||
public void testTeysaKarlovGitrogMonsterGitrogDies() {
|
||||
|
||||
Game game = initAndCreateGame();
|
||||
Player p = game.getPlayers().get(0);
|
||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
|
||||
|
||||
Card teysa = addCard("Teysa Karlov", p);
|
||||
addCard("The Gitrog Monster", p);
|
||||
addCard("Dryad Arbor", p);
|
||||
|
||||
String indestructibilityName = "Indestructibility";
|
||||
Card indestructibility = addCard(indestructibilityName, p);
|
||||
|
||||
indestructibility.attachToEntity(teysa);
|
||||
|
||||
// update Indestructible state
|
||||
game.getAction().checkStateEffects(true);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
addCard("Plains", p);
|
||||
addCardToZone("Plains", p, ZoneType.Library);
|
||||
}
|
||||
|
||||
Card armageddon = addCardToZone("Wrath of God", p, ZoneType.Hand);
|
||||
|
||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
||||
|
||||
SpellAbility armageddonSA = armageddon.getFirstSpellAbility();
|
||||
|
||||
GameSimulator sim = createSimulator(game, p);
|
||||
int score = sim.simulateSpellAbility(armageddonSA).value;
|
||||
assertTrue(score > 0);
|
||||
Game simGame = sim.getSimulatedGameState();
|
||||
|
||||
// One cards drawn
|
||||
assertTrue(simGame.getPlayers().get(0).getZone(ZoneType.Hand).size() == 1);
|
||||
}
|
||||
|
||||
public void testTeysaKarlovGitrogMonsterTeysaDies() {
|
||||
|
||||
Game game = initAndCreateGame();
|
||||
Player p = game.getPlayers().get(0);
|
||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
|
||||
|
||||
addCard("Teysa Karlov", p);
|
||||
Card gitrog = addCard("The Gitrog Monster", p);
|
||||
addCard("Dryad Arbor", p);
|
||||
|
||||
String indestructibilityName = "Indestructibility";
|
||||
Card indestructibility = addCard(indestructibilityName, p);
|
||||
|
||||
indestructibility.attachToEntity(gitrog);
|
||||
|
||||
// update Indestructible state
|
||||
game.getAction().checkStateEffects(true);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
addCard("Plains", p);
|
||||
addCardToZone("Plains", p, ZoneType.Library);
|
||||
}
|
||||
|
||||
Card armageddon = addCardToZone("Wrath of God", p, ZoneType.Hand);
|
||||
|
||||
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
|
||||
|
||||
SpellAbility armageddonSA = armageddon.getFirstSpellAbility();
|
||||
|
||||
GameSimulator sim = createSimulator(game, p);
|
||||
int score = sim.simulateSpellAbility(armageddonSA).value;
|
||||
assertTrue(score > 0);
|
||||
Game simGame = sim.getSimulatedGameState();
|
||||
|
||||
// One cards drawn
|
||||
assertTrue(simGame.getPlayers().get(0).getZone(ZoneType.Hand).size() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ Name:Dross Scorpion
|
||||
ManaCost:4
|
||||
Types:Artifact Creature Scorpion
|
||||
PT:3/1
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Artifact.Creature+Other | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigUntap | TriggerDescription$ Whenever CARDNAME or another artifact creature dies,
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | OptionalDecider$ You | Execute$ TrigUntap | TriggerDescription$ you may untap target artifact.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Artifact.Creature+Other | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigUntap | TriggerDescription$ Whenever CARDNAME or another artifact creature dies, you may untap target artifact.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | OptionalDecider$ You | Execute$ TrigUntap | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another artifact creature dies, you may untap target artifact.
|
||||
SVar:TrigUntap:DB$Untap | ValidTgts$ Artifact | TgtPrompt$ Choose target artifact.
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/dross_scorpion.jpg
|
||||
Oracle:Whenever Dross Scorpion or another artifact creature dies, you may untap target artifact.
|
||||
|
||||
@@ -2,7 +2,7 @@ Name:Naban, Dean of Iteration
|
||||
ManaCost:1 U
|
||||
Types:Legendary Creature Human Wizard
|
||||
PT:2/1
|
||||
S:Mode$ Continuous | Affected$ You | AddKeyword$ Panharmonicon:Wizard.YouCtrl | Description$ If a Wizard entering the battlefield under your control causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.
|
||||
K:Panharmonicon:Wizard.YouCtrl:If a Wizard entering the battlefield under your control causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.
|
||||
DeckHints:Type$Wizard
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/naban_dean_of_iteration.jpg
|
||||
Oracle:If a Wizard entering the battlefield under your control causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Name:Panharmonicon
|
||||
ManaCost:4
|
||||
Types:Artifact
|
||||
S:Mode$ Continuous | Affected$ You | AddKeyword$ Panharmonicon:Creature,Artifact | Description$ If an artifact or creature entering the battlefield causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.
|
||||
K:Panharmonicon:Creature,Artifact:If an artifact or creature entering the battlefield causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/panharmonicon.jpg
|
||||
Oracle:If an artifact or creature entering the battlefield causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.
|
||||
|
||||
@@ -2,6 +2,7 @@ Name:Awaken the Erstwhile
|
||||
ManaCost:3 B B
|
||||
Types:Sorcery
|
||||
A:SP$ RepeatEach | Cost$ 3 B B | RepeatPlayers$ Player | RepeatSubAbility$ DBDiscard | SpellDescription$ Each player discards all the cards in their hand, then creates that many 2/2 black Zombie creature tokens.
|
||||
SVar:DBToken:DB$ Token | TokenAmount$ X | TokenName$ Zombie | TokenTypes$ Creature,Zombie | TokenOwner$ You | TokenColors$ Black | TokenPower$ 2 | TokenToughness$ 2 | References$ X
|
||||
SVar:DBToken:DB$ Token | TokenAmount$ X | TokenScript$ b_2_2_zombie | TokenOwner$ You | LegacyImage$ b 2 2 zombie rna | References$ X
|
||||
SVar:X:Remembered$Amount
|
||||
DeckHas:Ability$Token
|
||||
Oracle:Each player discards all the cards in their hand, then creates that many 2/2 black Zombie creature tokens.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# TODO: -- THIS SCRIPT NEEDS REWRITING (non-functional) --
|
||||
Name:Captive Audience
|
||||
ManaCost:5 B R
|
||||
Types:Enchantment
|
||||
@@ -21,4 +22,5 @@ T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | E
|
||||
SVar:TrigChoose:DB$ ChooseCard | Defined$ You | Choices$ Player.Opponent | Mandatory$ True | SubAbility$ DBChangeZone
|
||||
SVar:DBChangeZone:DB$ ChangeZone | Defined$ Self | Origin$ All | Destination$ Battlefield | GainControl$ True
|
||||
SVar:RemRandomDeck:True
|
||||
DeckHas:Ability$Token
|
||||
Oracle:Captive Audience enters the battlefield under the control of an opponent of your choice.\nAt the beginning of your upkeep, choose one that hasn't been chosen —\n• Your life total becomes 4.\n• Discard your hand.\n• Each opponent creates five 2/2 black Zombie creature tokens.
|
||||
|
||||
@@ -11,7 +11,8 @@ ALTERNATE
|
||||
Name:Deploy
|
||||
ManaCost:2 W U
|
||||
Types:Instant
|
||||
A:SP$ Token | Cost$ 2 W U | TokenAmount$ 2 | TokenOwner$ You | TokenScript$ c_1_1_a_thopter_flying | SubAbility$ DBGainLife | SpellDescription$ Create two 1/1 colorless Thopter artifact creature tokens with flying, then you gain 1 life for each creature you control.
|
||||
A:SP$ Token | Cost$ 2 W U | TokenAmount$ 2 | TokenOwner$ You | TokenScript$ c_1_1_a_thopter_flying | LegacyImage$ c 1 1 a thopter flying rna | SubAbility$ DBGainLife | SpellDescription$ Create two 1/1 colorless Thopter artifact creature tokens with flying, then you gain 1 life for each creature you control.
|
||||
SVar:DBGainLife:DB$ GainLife | LifeAmount$ X | References$ X
|
||||
SVar:X:Count$TypeYouCtrl.Creature
|
||||
DeckHas:Ability$Token
|
||||
Oracle:Create two 1/1 colorless Thopter artifact creature tokens with flying, then you gain 1 life for each creature you control.
|
||||
|
||||
@@ -5,7 +5,7 @@ Loyalty:3
|
||||
A:AB$ Effect | Cost$ AddCounter<1/LOYALTY> | Name$ CARDNAME Effect | Triggers$ TrigSpellCast | SVars$ TrigPutCounter | SpellDescription$ Until end of turn, whenever a creature you control deals combat damage to a player, put a loyalty counter on CARDNAME.
|
||||
SVar:X:Count$Valid Creature.YouCtrl
|
||||
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ LOYALTY | CounterNum$ 1
|
||||
A:AB$ Token | Cost$ SubCounter<1/LOYALTY> | Planeswalker$ True | TokenAmount$ 1 | TokenName$ Thopter | TokenTypes$ Artifact,Creature,Thopter | TokenOwner$ You | TokenColors$ Colorless | TokenPower$ 1 | TokenToughness$ 1 | TokenKeywords$ Flying | SubAbility$ DBGainLife | SpellDescription$ Create a 1/1 colorless Thopter artifact creature token with flying.
|
||||
A:AB$ Token | Cost$ SubCounter<1/LOYALTY> | Planeswalker$ True | TokenAmount$ 1 | TokenScript$ c_1_1_a_thopter_flying | TokenOwner$ You | LegacyImage$ c 1 1 a thopter flying rna | SubAbility$ DBGainLife | SpellDescription$ Create a 1/1 colorless Thopter artifact creature token with flying.
|
||||
SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 1 | SpellDescription$ You gain 1 life.
|
||||
DeckHas:Ability$Token
|
||||
A:AB$ Dig | Cost$ SubCounter<7/LOYALTY> | Planeswalker$ True | DigNum$ 10 | ChangeNum$ 3 | DestinationZone$ Hand | DestinationZone2$ Library | LibraryPosition$ -1 | Choices$ Card.nonLand | SpellDescription$ Look at the top ten cards of your library. Put three of them into your hand and the rest on the bottom of your library in a random order.
|
||||
|
||||
@@ -6,4 +6,5 @@ T:Mode$ SpellCast | ValidCard$ Instant | ValidActivatingPlayer$ You | TriggerZon
|
||||
SVar:TrigGainLife:DB$GainLife | Defined$ You | LifeAmount$ 2 | SubAbility$ DBDraw
|
||||
SVar:DBDraw:DB$Draw | Defined$ You | NumCards$ 1
|
||||
SVar:X:Count$IfMainPhase
|
||||
DeckHas:Ability$LifeGain
|
||||
Oracle:When Dovin's Acuity enters the battlefield, you gain 2 life and draw a card.\nWhenever you cast an instant spell during your main phase, you may return Dovin's Acuity to its owner's hand.
|
||||
|
||||
@@ -6,7 +6,7 @@ S:Mode$ Continuous | Affected$ Creature.OppCtrl | AddPower$ -1 | AddToughness$ -
|
||||
SVar:PlayMain1:TRUE
|
||||
SVar:RemRandomDeck:True
|
||||
A:AB$ ChangeZone | Cost$ 4 W B | Origin$ Graveyard | Destination$ Exile | ValidTgts$ Card.OppOwn | SubAbility$ DBToken | SpellDescription$ Exile target card from an opponent's graveyard. If it was a creature card, you create a 1/1 white and black Spirit creature token with flying.
|
||||
SVar:DBToken:DB$ Token | ConditionDefined$ Targeted | ConditionPresent$ Creature | ConditionCompare$ EQ1 | TokenAmount$ 1 | TokenScript$ wb_1_1_spirit_flying | TokenOwner$ You | SubAbility$ DBCleanup
|
||||
SVar:DBToken:DB$ Token | ConditionDefined$ Targeted | ConditionPresent$ Creature | ConditionCompare$ EQ1 | TokenAmount$ 1 | TokenScript$ wb_1_1_spirit_flying | TokenOwner$ You | SubAbility$ DBCleanup | LegacyImage$ wb 1 1 spirit flying rna
|
||||
SVar:DBCleanup:DB$Cleanup | ClearRemembered$ True
|
||||
DeckHas:Ability$Token
|
||||
Oracle:Creatures you control get +1/+1.\nCreatures your opponents control get -1/-1.\n{2}{W}{B}: Exile target card from an opponent's graveyard. If it was a creature card, you create a 1/1 white and black Spirit creature token with flying.
|
||||
|
||||
@@ -4,6 +4,6 @@ Types:Creature Human Shaman
|
||||
PT:2/2
|
||||
K:Haste
|
||||
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigSacrifice | TriggerDescription$ At the beginning of your upkeep, you may sacrifice a creature. When you do, CARDNAME deals 2 damage to target opponent or planeswalker.
|
||||
SVar:TrigSacrifice:DB$ Sacrifice | Optional$ True | SacValid$ Creature | Amount$ 1 | AILogic$ CARDNAME
|
||||
SVar:TrigSacrifice:DB$ Sacrifice | Optional$ True | SacValid$ Creature | Amount$ 1
|
||||
SVar:TrigDealDamage:DB$ DealDamage | ValidTgts$ Opponent,Planeswalker | TgtPrompt$ Select target opponent or planeswalker | NumDmg$ 2
|
||||
Oracle:Haste\nAt the beginning of your upkeep, you may sacrifice a creature. When you do, Fireblade Artist deals 2 damage to target opponent or planeswalker.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Name:Goblin Gathering
|
||||
ManaCost:2 R
|
||||
Types:Sorcery
|
||||
A:SP$ Token | Cost$ 2 R | TokenAmount$ X | TokenScript$ r_1_1_goblin | TokenOwner$ You | References$ X | SpellDescription$ Create a number of 1/1 red Goblin creature tokens equal to two plus the number of cards named CARDNAME in your graveyard.
|
||||
A:SP$ Token | Cost$ 2 R | TokenAmount$ X | TokenScript$ r_1_1_goblin | LegacyImage$ r 1 1 goblin rna | TokenOwner$ You | References$ X | SpellDescription$ Create a number of 1/1 red Goblin creature tokens equal to two plus the number of cards named Goblin Gathering in your graveyard.
|
||||
SVar:X:Count$ValidGraveyard Card.YouOwn+namedGoblin Gathering/Plus.2
|
||||
DeckHints:Name$Goblin Gathering
|
||||
DeckHas:Ability$Token
|
||||
|
||||
@@ -10,4 +10,5 @@ A:AB$ ChangeZone | Cost$ -1/-1/Card.nonLand/nonland permanent with converted man
|
||||
A:AB$ DealDamage | Cost$ PayLife<5/-5/Card> | Planeswalker$ True | Ultimate$ True | ValidTgts$ Player | NumDmg$ X | References$ X | SubAbility$ DBYouGainLife | SpellDescription$ CARDNAME deals damage to target player equal to the number of cards that player owns in exile and you gain that much life.
|
||||
SVar:DBYouGainLife:DB$ GainLife | Defined$ You | LifeAmount$ X | References$ X
|
||||
SVar:X:TargetedPlayer$CardsInExile
|
||||
DeckHas:Ability$LifeGain
|
||||
Oracle:[+1]: Exile up to two target cards from a single graveyard. You gain 2 life if at least one creature card was exiled this way.\n[-1]: Exile target nonland permanent with converted mana cost 1 or less.\n[-5]: Kaya, Orzhov Usurper deals damage to target player equal to the number of cards that player owns in exile and you gain that much life.
|
||||
|
||||
@@ -4,4 +4,5 @@ Types:Sorcery
|
||||
A:SP$ DestroyAll | Cost$ W W B B | ValidCards$ Creature | RememberDestroyed$ True | SubAbility$ DBGainLife | SpellDescription$ Destroy all creatures. You gain life equal to the number of creatures you controlled that were destroyed this way.
|
||||
SVar:DBGainLife:DB$ GainLife | LifeAmount$ X | References$ X
|
||||
SVar:X:RememberedLKI$FilterControlledByRemembered_Number$1
|
||||
DeckHas:Ability$LifeGain
|
||||
Oracle:Destroy all creatures. You gain life equal to the number of creatures you controlled that were destroyed this way.
|
||||
|
||||
@@ -2,7 +2,7 @@ Name:Knight of the Last Breath
|
||||
ManaCost:5 W B
|
||||
Types:Creature Giant Knight
|
||||
PT:4/4
|
||||
A:AB$ Token | Cost$ 3 Sac<1/Creature.nonToken+Other/another creature> | TokenAmount$ 1 | TokenScript$ wb_1_1_spirit_flying | TokenOwner$ You | SpellDescription$ Create a 1/1 white and black Spirit creature token with flying.
|
||||
A:AB$ Token | Cost$ 3 Sac<1/Creature.nonToken+Other/another creature> | TokenAmount$ 1 | TokenScript$ wb_1_1_spirit_flying | TokenOwner$ You | LegacyImage$ wb 1 1 spirit flying rna | SpellDescription$ Create a 1/1 white and black Spirit creature token with flying.
|
||||
SVar:RemRandomDeck:True
|
||||
K:Afterlife:3
|
||||
SVar:AIPreference:SacCost$Creature.cmcLE1
|
||||
|
||||
@@ -3,10 +3,12 @@ ManaCost:3 U U
|
||||
Types:Creature Octopus
|
||||
PT:4/5
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield, create two 0/2 blue Illusion creature tokens with flying, it doesn't untap during its controller's next untap step.
|
||||
SVar:TrigToken:DB$ Token | TokenAmount$ 2 | TokenName$ Illusion | TokenTypes$ Creature,Illusion | TokenOwner$ You | TokenColors$ Blue | TokenPower$ 0 | TokenToughness$ 2 | TokenKeywords$ HIDDEN This card doesn't untap during your next untap step. | Permanent$ True
|
||||
SVar:TrigToken:DB$ Token | TokenAmount$ 2 | TokenScript$ u_0_2_illusion_mesmerize | TokenOwner$ You | LegacyImage$ u 0 2 illusion mesmerize rna
|
||||
SVar:PlayMain1:TRUE
|
||||
SVar:RemRandomDeck:True
|
||||
S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ Hexproof | CheckSVar$ X | SVarCompare$ GE1 | Description$ CARDNAME has hexproof as long as you control an Illusion.
|
||||
SVar:X:Count$Valid Illusion.YouCtrl
|
||||
SVar:BuffedBy:Illusion
|
||||
DeckHas:Ability$Token
|
||||
DeckHints:Type$Illusion
|
||||
Oracle:When Mesmerizing Benthid enters the battlefield, create two 0/2 blue Illusion creature tokens with "Whenever this creature blocks a creature, that creature doesn't untap during its controller's next untap step."\nMesmerizing Benthid has hexproof as long as you control an Illusion.
|
||||
|
||||
@@ -5,4 +5,5 @@ T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creatu
|
||||
SVar:TrigFlipACoin:DB$FlipACoin | FlipUntilYouLose$ True | SaveNumFlipsToSVar$ MirrorAmount | NoCall$ True | LoseSubAbility$ DBCopies
|
||||
SVar:DBCopies:DB$ CopyPermanent | PumpKeywords$ Haste | AtEOT$ Exile | Defined$ TriggeredCard | NumCopies$ MirrorAmount
|
||||
SVar:MirrorAmount:Number$0
|
||||
DeckHas:Ability$Token
|
||||
Oracle:Whenever a nontoken creature enters the battlefield under your control, flip a coin until you lose a flip. For each flip you won, create a token that's a copy of that creature. Those tokens gain haste. Exile them at the beginning of the next end step.
|
||||
|
||||
@@ -7,5 +7,6 @@ K:Trample
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigFlip | TriggerDescription$ When CARDNAME enters the battlefield, flip a coin for each creature that isn't a Demon, Dragons, or coins. Destroy each creature whose coin comes up tails.
|
||||
SVar:TrigFlip:DB$ FlipACoin | FlipUntilYouLose$ True | SaveNumFlipsToSVar$ X | LoseSubAbility$ DBDestroy
|
||||
SVar:DBDestroy:DB$ DestroyAll | ValidCards$ Creature.IsNotChosenType | References$ X
|
||||
# TODO: -- THIS LINE NEEDS FIXING (doesn't reference the types correctly) --
|
||||
SVar:X:Count$Valid Creature.isn
|
||||
Oracle:Flying, trample\nWhen Rakdos, the Showstopper enters the battlefield, flip a coin for each creature that isn't a Demon, Devil, or Imp. Destroy each creature whose coin comes up tails.
|
||||
|
||||
@@ -12,4 +12,5 @@ Name:Replicate
|
||||
ManaCost:1 G U
|
||||
Types:Sorcery
|
||||
A:SP$ CopyPermanent | Cost$ 1 G U | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | SpellDescription$ Create a token that's a copy of target creature you control.
|
||||
DeckHas:Ability$Token
|
||||
Oracle:Create a token that’s a copy of target creature you control.
|
||||
|
||||
@@ -5,4 +5,5 @@ PT:6/6
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigEffect | TriggerDescription$ When CARDNAME enters the battlefield, your number of +1/+1 counters on creatures you control. Creatures your opponents control with power less than or equal to that number can't block this turn.
|
||||
SVar:TrigEffect:DB$Effect | Name$ CARDNAME Effect | StaticAbilities$ KWPump
|
||||
SVar:KWPump:Mode$ Continuous | EffectZone$ Command | Affected$ Creature.YouCtrl+powerLTY | AddHiddenKeyword$ CARDNAME can't block. | Description$ Creatures your opponents control with power less than or equal to that number can't block this turn.
|
||||
# TODO: -- THIS SCRIPT NEEDS FIXING (doesn't have the count var) --
|
||||
Oracle:When Rumbling Ruin enters the battlefield, count the number of +1/+1 counters on creatures you control. Creatures your opponents control with power less than or equal to that number can't block this turn.
|
||||
|
||||
@@ -2,6 +2,6 @@ Name:Smothering Tithe
|
||||
ManaCost:3 W
|
||||
Types:Enchantment
|
||||
T:Mode$ Drawn | ValidCard$ Card.OppOwn | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever an opponent draws a card, that player may pay {2}. If the player doesn't, you create a colorless Treasure artifact token with flying{T}, Sacrifice this artifact: Add one mana of any color.
|
||||
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenName$ Treasure | TokenTypes$ Artifact,Treasure | TokenOwner$ TriggeredPlayer | TokenColors$ Colorless | TokenImage$ c treasure | TokenAbilities$ ABTreasureMana | TokenAltImages$ c_treasure2,c_treasure3,c_treasure4
|
||||
SVar:ABTreasureMana:DB$ Token | TokenAmount$ 1 | TokenName$
|
||||
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_a_treasure_sac | TokenOwner$ TriggeredPlayer | LegacyImage$ c treasure
|
||||
DeckHas:Ability$Token
|
||||
Oracle:Whenever an opponent draws a card, that player may pay {2}. If the player doesn't, you create a colorless Treasure artifact token with "{T}, Sacrifice this artifact: Add one mana of any color."
|
||||
|
||||
@@ -2,7 +2,7 @@ Name:Teysa Karlov
|
||||
ManaCost:2 W B
|
||||
Types:Legendary Creature Human Advisor
|
||||
PT:2/4
|
||||
S:Mode$ Continuous | Affected$ You | AddKeyword$ Dieharmonicon | Description$ If a creature dying causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.
|
||||
K:Dieharmonicon:Creature:If a creature dying causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.
|
||||
S:Mode$ Continuous | Affected$ Creature.token+YouCtrl | AddKeyword$ Vigilance & Lifelink | Description$ Creature tokens you control have vigilance and lifelink.
|
||||
DeckHints:Ability$Token
|
||||
Oracle:If a creature dying causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.\nCreature tokens you control have vigilance and lifelink.
|
||||
|
||||
@@ -12,5 +12,6 @@ ALTERNATE
|
||||
Name:Threat
|
||||
ManaCost:2 R G
|
||||
Types:Sorcery
|
||||
A:SP$ Token | Cost$ 2 R G | TokenAmount$ 1 | TokenOwner$ You | TokenScript$ rg_4_4_beast_trample | SpellDescription$ Create a 4/4 red and green Beast creature token with trample.
|
||||
A:SP$ Token | Cost$ 2 R G | TokenAmount$ 1 | TokenOwner$ You | TokenScript$ rg_4_4_beast_trample | LegacyImage$ rg 4 4 beast trample rna | SpellDescription$ Create a 4/4 red and green Beast creature token with trample.
|
||||
DeckHas:Ability$Token
|
||||
Oracle:Create a 4/4 red and green Beast creature token with trample.
|
||||
@@ -10,7 +10,7 @@ ALTERNATE
|
||||
Name:Warden
|
||||
ManaCost:3 W U
|
||||
Types:Sorcery
|
||||
A:SP$ Token | Cost$ 3 W U | TokenAmount$ 1 | TokenOwner$ You | TokenScript$ wu_4_4_sphinx_flying_vigilance | SpellDescription$ Create a 4/4 white and blue Sphinx creature token with flying and vigilance.
|
||||
A:SP$ Token | Cost$ 3 W U | TokenAmount$ 1 | TokenOwner$ You | TokenScript$ wu_4_4_sphinx_flying_vigilance | LegacyImage$ wu 4 4 sphinx flying vigilance rna | SpellDescription$ Create a 4/4 white and blue Sphinx creature token with flying and vigilance.
|
||||
Oracle:Create a 4/4 white and blue Sphinx creature token with flying and vigilance.
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ ManaCost:5 W
|
||||
Types:Creature Giant Soldier
|
||||
PT:3/6
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield, create a 1/1 white Human creature token.
|
||||
SVar:TrigToken:DB$Token | TokenAmount$ 1 | TokenScript$ w_1_1_human | TokenOwner$ You | SpellDescription$ Create a 1/1 white Human creature token.
|
||||
SVar:TrigToken:DB$Token | TokenAmount$ 1 | TokenScript$ w_1_1_human | LegacyImage$ w 1 1 human rna | TokenOwner$ You | SpellDescription$ Create a 1/1 white Human creature token.
|
||||
DeckHints:Type$Human
|
||||
DeckHas:Ability$Token
|
||||
Oracle:When Watchful Giant enters the battlefield, create a 1/1 white Human creature token.
|
||||
|
||||
@@ -38,6 +38,7 @@ b_2_2_zombie_m13.jpg https://downloads.cardforge.org/images/to
|
||||
b_2_2_zombie_m14.jpg https://downloads.cardforge.org/images/tokens/b_2_2_zombie_m14.jpg
|
||||
b_2_2_zombie_mbs.jpg https://downloads.cardforge.org/images/tokens/b_2_2_zombie_mbs.jpg
|
||||
b_2_2_zombie_knight.jpg https://downloads.cardforge.org/images/tokens/b_2_2_zombie_knight.jpg
|
||||
b_2_2_zombie_rna.jpg https://downloads.cardforge.org/images/tokens/b_2_2_zombie_rna.jpg
|
||||
b_2_4_spider.jpg https://downloads.cardforge.org/images/tokens/b_2_4_spider.jpg
|
||||
b_3_3_angel.jpg https://downloads.cardforge.org/images/tokens/b_3_3_angel.jpg
|
||||
b_3_3_kavu.jpg https://downloads.cardforge.org/images/tokens/b_3_3_kavu.jpg
|
||||
@@ -65,6 +66,7 @@ c_0_1_pest.jpg https://downloads.cardforge.org/images/to
|
||||
c_0_1_prism.jpg https://downloads.cardforge.org/images/tokens/c_0_1_prism.jpg
|
||||
c_0_2_wall.jpg https://downloads.cardforge.org/images/tokens/c_0_2_wall.jpg
|
||||
c_10_10_eldrazi.jpg https://downloads.cardforge.org/images/tokens/c_10_10_eldrazi.jpg
|
||||
c_1_1_a_thopter_flying_rna.jpg https://downloads.cardforge.org/images/tokens/c_1_1_a_thopter_flying_rna.jpg
|
||||
c_1_1_eldrazi_scion.jpg https://downloads.cardforge.org/images/tokens/c_1_1_eldrazi_scion.jpg
|
||||
c_1_1_eldrazi_scion2.jpg https://downloads.cardforge.org/images/tokens/c_1_1_eldrazi_scion2.jpg
|
||||
c_1_1_eldrazi_scion3.jpg https://downloads.cardforge.org/images/tokens/c_1_1_eldrazi_scion3.jpg
|
||||
@@ -103,6 +105,7 @@ c_5_5_tuktuk_the_returned.jpg https://downloads.cardforge.org/images/to
|
||||
c_6_12_construct.jpg https://downloads.cardforge.org/images/tokens/c_6_12_construct.jpg
|
||||
c_7_7_eldrazi.jpg https://downloads.cardforge.org/images/tokens/c_7_7_eldrazi.jpg
|
||||
c_9_9_golem.jpg https://downloads.cardforge.org/images/tokens/c_9_9_golem.jpg
|
||||
c_a_treasure_sac_rna.jpg https://downloads.cardforge.org/images/tokens/c_a_treasure_sac_rna.jpg
|
||||
c_gold.jpg https://downloads.cardforge.org/images/tokens/c_gold.jpg
|
||||
c_x_x_horror.jpg https://downloads.cardforge.org/images/tokens/c_x_x_horror.jpg
|
||||
c_x_x_riptide_replicator.jpg https://downloads.cardforge.org/images/tokens/c_x_x_riptide_replicator.jpg
|
||||
@@ -154,6 +157,7 @@ g_2_2_boar.jpg https://downloads.cardforge.org/images/to
|
||||
g_2_2_cat_warrior.jpg https://downloads.cardforge.org/images/tokens/g_2_2_cat_warrior.jpg
|
||||
g_2_2_lizard.jpg https://downloads.cardforge.org/images/tokens/g_2_2_lizard.jpg
|
||||
g_2_2_ooze.jpg https://downloads.cardforge.org/images/tokens/g_2_2_ooze.jpg
|
||||
g_2_2_ooze_rna.jpg https://downloads.cardforge.org/images/tokens/g_2_2_ooze_rna.jpg
|
||||
g_2_2_wolf.jpg https://downloads.cardforge.org/images/tokens/g_2_2_wolf.jpg
|
||||
g_2_2_wolf_bng.jpg https://downloads.cardforge.org/images/tokens/g_2_2_wolf_bng.jpg
|
||||
g_2_2_wolf_isd.jpg https://downloads.cardforge.org/images/tokens/g_2_2_wolf_isd.jpg
|
||||
@@ -176,11 +180,13 @@ g_3_3_boar.jpg https://downloads.cardforge.org/images/to
|
||||
g_3_3_centaur.jpg https://downloads.cardforge.org/images/tokens/g_3_3_centaur.jpg
|
||||
g_3_3_centaur_bng.jpg https://downloads.cardforge.org/images/tokens/g_3_3_centaur_bng.jpg
|
||||
g_3_3_centaur_pro_black.jpg https://downloads.cardforge.org/images/tokens/g_3_3_centaur_pro_black.jpg
|
||||
g_3_3_centaur_rna.jpg https://downloads.cardforge.org/images/tokens/g_3_3_centaur_rna.jpg
|
||||
g_3_3_centaur_rtr.jpg https://downloads.cardforge.org/images/tokens/g_3_3_centaur_rtr.jpg
|
||||
g_3_3_elephant.jpg https://downloads.cardforge.org/images/tokens/g_3_3_elephant.jpg
|
||||
g_3_3_elephant_ody.jpg https://downloads.cardforge.org/images/tokens/g_3_3_elephant_ody.jpg
|
||||
g_3_3_elephant_wwk.jpg https://downloads.cardforge.org/images/tokens/g_3_3_elephant_wwk.jpg
|
||||
g_3_3_frog_lizard.jpg https://downloads.cardforge.org/images/tokens/g_3_3_frog_lizard.jpg
|
||||
g_3_3_frog_lizard_rna.jpg https://downloads.cardforge.org/images/tokens/g_3_3_frog_lizard_rna.jpg
|
||||
g_4_4_beast.jpg https://downloads.cardforge.org/images/tokens/g_4_4_beast.jpg
|
||||
g_4_4_beast_zen.jpg https://downloads.cardforge.org/images/tokens/g_4_4_beast_zen.jpg
|
||||
g_4_4_elemental.jpg https://downloads.cardforge.org/images/tokens/g_4_4_elemental.jpg
|
||||
@@ -221,6 +227,7 @@ r_1_1_goblin_dom.jpg https://downloads.cardforge.org/images/to
|
||||
r_1_1_goblin_m13.jpg https://downloads.cardforge.org/images/tokens/r_1_1_goblin_m13.jpg
|
||||
r_1_1_goblin_nph.jpg https://downloads.cardforge.org/images/tokens/r_1_1_goblin_nph.jpg
|
||||
r_1_1_goblin_rav.jpg https://downloads.cardforge.org/images/tokens/r_1_1_goblin_rav.jpg
|
||||
r_1_1_goblin_rna.jpg https://downloads.cardforge.org/images/tokens/r_1_1_goblin_rna.jpg
|
||||
r_1_1_goblin_rtr.jpg https://downloads.cardforge.org/images/tokens/r_1_1_goblin_rtr.jpg
|
||||
r_1_1_goblin_scout.jpg https://downloads.cardforge.org/images/tokens/r_1_1_goblin_scout.jpg
|
||||
r_1_1_goblin_som.jpg https://downloads.cardforge.org/images/tokens/r_1_1_goblin_som.jpg
|
||||
@@ -261,6 +268,7 @@ rg_1_1_goblin_warrior.jpg https://downloads.cardforge.org/images/to
|
||||
rg_2_2_satyr.jpg https://downloads.cardforge.org/images/tokens/rg_2_2_satyr.jpg
|
||||
rg_3_4_stangg_twin.jpg https://downloads.cardforge.org/images/tokens/rg_3_4_stangg_twin.jpg
|
||||
rg_4_4_giant_warrior.jpg https://downloads.cardforge.org/images/tokens/rg_4_4_giant_warrior.jpg
|
||||
rg_4_4_beast_trample_rna.jpg https://downloads.cardforge.org/images/tokens/rg_4_4_beast_trample.jpg
|
||||
rg_5_5_elemental.jpg https://downloads.cardforge.org/images/tokens/rg_5_5_elemental.jpg
|
||||
rw_1_1_goblin_soldier.jpg https://downloads.cardforge.org/images/tokens/rw_1_1_goblin_soldier.jpg
|
||||
rw_1_1_goblin_soldier_eve.jpg https://downloads.cardforge.org/images/tokens/rw_1_1_goblin_soldier_eve.jpg
|
||||
@@ -268,6 +276,7 @@ rw_1_1_soldier.jpg https://downloads.cardforge.org/images/to
|
||||
u_0_1_homunculus.jpg https://downloads.cardforge.org/images/tokens/u_0_1_homunculus.jpg
|
||||
u_0_1_plant_wall.jpg https://downloads.cardforge.org/images/tokens/u_0_1_plant_wall.jpg
|
||||
u_0_1_starfish.jpg https://downloads.cardforge.org/images/tokens/u_0_1_starfish.jpg
|
||||
u_0_2_illusion_mesmerize_rna.jpg https://downloads.cardforge.org/images/tokens/u_0_2_illusion_mesmerize_rna.jpg
|
||||
u_1_0_elemental.jpg https://downloads.cardforge.org/images/tokens/u_1_0_elemental.jpg
|
||||
u_1_1_bird.jpg https://downloads.cardforge.org/images/tokens/u_1_1_bird.jpg
|
||||
u_1_1_bird_eve.jpg https://downloads.cardforge.org/images/tokens/u_1_1_bird_eve.jpg
|
||||
@@ -309,6 +318,7 @@ w_1_1_citizen.jpg https://downloads.cardforge.org/images/to
|
||||
w_1_1_goldmeadow_harrier.jpg https://downloads.cardforge.org/images/tokens/w_1_1_goldmeadow_harrier.jpg
|
||||
w_1_1_human.jpg https://downloads.cardforge.org/images/tokens/w_1_1_human.jpg
|
||||
w_1_1_human_avr.jpg https://downloads.cardforge.org/images/tokens/w_1_1_human_avr.jpg
|
||||
w_1_1_human_rna.jpg https://downloads.cardforge.org/images/tokens/w_1_1_human_rna.jpg
|
||||
w_1_1_kithkin_soldier.jpg https://downloads.cardforge.org/images/tokens/w_1_1_kithkin_soldier.jpg
|
||||
w_1_1_kithkin_soldier_shm.jpg https://downloads.cardforge.org/images/tokens/w_1_1_kithkin_soldier_shm.jpg
|
||||
w_1_1_knight.jpg https://downloads.cardforge.org/images/tokens/w_1_1_knight.jpg
|
||||
@@ -366,13 +376,15 @@ w_x_x_reflection.jpg https://downloads.cardforge.org/images/to
|
||||
wb_1_1_cleric.jpg https://downloads.cardforge.org/images/tokens/wb_1_1_cleric.jpg
|
||||
wb_1_1_spirit.jpg https://downloads.cardforge.org/images/tokens/wb_1_1_spirit.jpg
|
||||
wb_1_1_spirit_gtc.jpg https://downloads.cardforge.org/images/tokens/wb_1_1_spirit_gtc.jpg
|
||||
wb_1_1_spirit_rna.jpg https://downloads.cardforge.org/images/tokens/wb_1_1_spirit_rna.jpg
|
||||
wrg_8_8_beast.jpg https://downloads.cardforge.org/images/tokens/wrg_8_8_beast.jpg
|
||||
wu_1_1_bird.jpg https://downloads.cardforge.org/images/tokens/wu_1_1_bird.jpg
|
||||
|
||||
wu_4_4_sphinx_flying_vigilance_rna.jpg https://downloads.cardforge.org/images/tokens/wu_4_4_sphinx_flying_vigilance_rna.jpg
|
||||
|
||||
|
||||
# Emblems
|
||||
chandra_the_firebrand_effect.jpg https://downloads.cardforge.org/images/tokens/chandra_the_firebrand_effect.jpg
|
||||
emblem_domri_chaos_bringer_rna.jpg https://downloads.cardforge.org/images/tokens/emblem_domri_chaos_bringer_rna.jpg
|
||||
emblem_domri_rade.jpg https://downloads.cardforge.org/images/tokens/emblem_domri_rade.jpg
|
||||
emblem_elspeth_knight_errant.jpg https://downloads.cardforge.org/images/tokens/emblem_elspeth_knight_errant.jpg
|
||||
emblem_elspeth_suns_champion.jpg https://downloads.cardforge.org/images/tokens/emblem_elspeth_suns_champion.jpg
|
||||
|
||||
5
forge-gui/res/tokenscripts/c_a_treasure_sac.txt
Normal file
5
forge-gui/res/tokenscripts/c_a_treasure_sac.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Name:Treasure
|
||||
ManaCost:no cost
|
||||
Types:Artifact Treasure
|
||||
A:AB$ Mana | Cost$ T Sac<1/CARDNAME|this artifact> | Produced$ Any | Amount$ 1 | SpellDescription$ Add one mana of any color.
|
||||
Oracle:{T}, Sacrifice this artifact: Add one mana of any color.
|
||||
9
forge-gui/res/tokenscripts/u_0_2_illusion_mesmerize.txt
Normal file
9
forge-gui/res/tokenscripts/u_0_2_illusion_mesmerize.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
Name:Illusion
|
||||
Types:Creature Illusion
|
||||
ManaCost:no cost
|
||||
Colors:blue
|
||||
PT:0/2
|
||||
T:Mode$ AttackerBlocked | ValidBlocker$ Card.Self | Execute$ TrigPump | TriggerDescription$ Whenever this creature blocks a creature, that creature doesn't untap during its controller's next untap step.
|
||||
SVar:TrigPump:DB$ Pump | Defined$ TriggeredAttacker | KW$ HIDDEN This card doesn't untap during your next untap step. | Permanent$ True
|
||||
SVar:HasBlockEffect:TRUE
|
||||
Oracle:Whenever this creature blocks a creature, that creature doesn't untap during its controller's next untap step.
|
||||
@@ -69,7 +69,7 @@ public class InputSelectFromTwoLists<T extends GameEntity> extends InputSelectMa
|
||||
if ( valid1.contains(s) ) { selected1 = true; }
|
||||
if ( valid2.contains(s) ) { selected2 = true; }
|
||||
}
|
||||
validChoices = selected1 ? ( selected2 ? FCollection.getEmpty() : valid2 ) : ( selected2 ? valid1 : validBoth );
|
||||
validChoices = selected1 ? ( selected2 ? FCollection.<T>getEmpty() : valid2 ) : ( selected2 ? valid1 : validBoth );
|
||||
setSelectables();
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override public void run() {
|
||||
|
||||
Reference in New Issue
Block a user