Update getDefinedCards for how it get Valid* cards so the syntax is consistent with other Valid script. Also remove the hacky way to set Effect as mutable for Raging River and Plague of Vermin

This commit is contained in:
Hans Mackowiak
2021-07-18 09:06:47 +00:00
committed by Alumi
parent 52160c9e60
commit e753d45b42
28 changed files with 111 additions and 106 deletions

View File

@@ -229,12 +229,12 @@ public class GameCopier {
private static final boolean USE_FROM_PAPER_CARD = true; private static final boolean USE_FROM_PAPER_CARD = true;
private Card createCardCopy(Game newGame, Player newOwner, Card c) { private Card createCardCopy(Game newGame, Player newOwner, Card c) {
if (c.isToken() && !c.isEmblem()) { if (c.isToken() && !c.isImmutable()) {
Card result = new TokenInfo(c).makeOneToken(newOwner); Card result = new TokenInfo(c).makeOneToken(newOwner);
CardFactory.copyCopiableCharacteristics(c, result); CardFactory.copyCopiableCharacteristics(c, result);
return result; return result;
} }
if (USE_FROM_PAPER_CARD && !c.isEmblem() && c.getPaperCard() != null) { if (USE_FROM_PAPER_CARD && !c.isImmutable() && c.getPaperCard() != null) {
Card newCard = Card.fromPaperCard(c.getPaperCard(), newOwner); Card newCard = Card.fromPaperCard(c.getPaperCard(), newOwner);
newCard.setCommander(c.isCommander()); newCard.setCommander(c.isCommander());
return newCard; return newCard;

View File

@@ -58,7 +58,6 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
Conspiracy(false, "conspiracies"), Conspiracy(false, "conspiracies"),
Creature(true, "creatures"), Creature(true, "creatures"),
Dungeon(false, "dungeons"), Dungeon(false, "dungeons"),
Emblem(false, "emblems"),
Enchantment(true, "enchantments"), Enchantment(true, "enchantments"),
Instant(false, "instants"), Instant(false, "instants"),
Land(true, "lands"), Land(true, "lands"),
@@ -437,11 +436,6 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
return coreTypes.contains(CoreType.Phenomenon); return coreTypes.contains(CoreType.Phenomenon);
} }
@Override
public boolean isEmblem() {
return coreTypes.contains(CoreType.Emblem);
}
@Override @Override
public boolean isTribal() { public boolean isTribal() {
return coreTypes.contains(CoreType.Tribal); return coreTypes.contains(CoreType.Tribal);
@@ -547,7 +541,7 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
if (!isInstant() && !isSorcery()) { if (!isInstant() && !isSorcery()) {
Iterables.removeIf(subtypes, Predicates.IS_SPELL_TYPE); Iterables.removeIf(subtypes, Predicates.IS_SPELL_TYPE);
} }
if (!isPlaneswalker() && !isEmblem()) { if (!isPlaneswalker()) {
Iterables.removeIf(subtypes, Predicates.IS_WALKER_TYPE); Iterables.removeIf(subtypes, Predicates.IS_WALKER_TYPE);
} }
} }

View File

@@ -42,7 +42,6 @@ public interface CardTypeView extends Iterable<String>, Serializable {
boolean isBasicLand(); boolean isBasicLand();
boolean isPlane(); boolean isPlane();
boolean isPhenomenon(); boolean isPhenomenon();
boolean isEmblem();
boolean isTribal(); boolean isTribal();
boolean isDungeon(); boolean isDungeon();
CardTypeView getTypeWithChanges(Iterable<CardChangedType> changedCardTypes); CardTypeView getTypeWithChanges(Iterable<CardChangedType> changedCardTypes);

View File

@@ -153,8 +153,7 @@ public final class GameActionUtil {
final StringBuilder sb = new StringBuilder(sa.getDescription()); final StringBuilder sb = new StringBuilder(sa.getDescription());
if (!source.equals(host)) { if (!source.equals(host)) {
sb.append(" by "); sb.append(" by ");
if ((host.isEmblem() || host.getType().hasSubtype("Effect")) if ((host.isImmutable()) && host.getEffectSource() != null) {
&& host.getEffectSource() != null) {
sb.append(host.getEffectSource()); sb.append(host.getEffectSource());
} else { } else {
sb.append(host); sb.append(host);
@@ -542,7 +541,6 @@ public final class GameActionUtil {
final Card eff = new Card(game.nextCardId(), game); final Card eff = new Card(game.nextCardId(), game);
eff.setTimestamp(game.getNextTimestamp()); eff.setTimestamp(game.getNextTimestamp());
eff.setName(sourceCard.getName() + "'s Effect"); eff.setName(sourceCard.getName() + "'s Effect");
eff.addType("Effect");
eff.setOwner(controller); eff.setOwner(controller);
eff.setImageKey(sourceCard.getImageKey()); eff.setImageKey(sourceCard.getImageKey());

View File

@@ -112,9 +112,9 @@ public class AbilityUtils {
// Probably will move to One function solution sometime in the future // Probably will move to One function solution sometime in the future
public static CardCollection getDefinedCards(final Card hostCard, final String def, final CardTraitBase sa) { public static CardCollection getDefinedCards(final Card hostCard, final String def, final CardTraitBase sa) {
CardCollection cards = new CardCollection(); CardCollection cards = new CardCollection();
String defined = (def == null) ? "Self" : applyAbilityTextChangeEffects(def, sa); // default to Self String changedDef = (def == null) ? "Self" : applyAbilityTextChangeEffects(def, sa); // default to Self
final String[] incR = defined.split("\\.", 2); final String[] incR = changedDef.split("\\.", 2);
defined = incR[0]; String defined = incR[0];
final Game game = hostCard.getGame(); final Game game = hostCard.getGame();
Card c = null; Card c = null;
@@ -132,7 +132,7 @@ public class AbilityUtils {
} }
} }
else if (defined.equals("EffectSource")) { else if (defined.equals("EffectSource")) {
if (hostCard.isEmblem() || hostCard.getType().hasSubtype("Effect")) { if (hostCard.isImmutable()) {
c = findEffectRoot(hostCard); c = findEffectRoot(hostCard);
} }
} }
@@ -346,6 +346,23 @@ public class AbilityUtils {
cards.add(game.getCardState(cardByID)); cards.add(game.getCardState(cardByID));
} }
} }
} else if (defined.startsWith("Valid")) {
Iterable<Card> candidates;
String validDefined;
if (defined.startsWith("Valid ")) {
candidates = game.getCardsIn(ZoneType.Battlefield);
validDefined = changedDef.substring("Valid ".length());
} else if (defined.startsWith("ValidAll ")) {
candidates = game.getCardsInGame();
validDefined = changedDef.substring("ValidAll ".length());
} else {
String[] s = changedDef.split(" ", 2);
String zone = s[0].substring("Valid".length());
candidates = game.getCardsIn(ZoneType.smartValueOf(zone));
validDefined = s[1];
}
cards.addAll(CardLists.getValidCards(candidates, validDefined.split(","), hostCard.getController(), hostCard, sa));
return cards;
} else { } else {
CardCollection list = null; CardCollection list = null;
if (sa instanceof SpellAbility) { if (sa instanceof SpellAbility) {
@@ -377,19 +394,6 @@ public class AbilityUtils {
} }
} }
if (defined.startsWith("Valid ")) {
String validDefined = defined.substring("Valid ".length());
list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), validDefined.split(","), hostCard.getController(), hostCard, sa);
} else if (defined.startsWith("ValidAll ")) {
String validDefined = defined.substring("ValidAll ".length());
list = CardLists.getValidCards(game.getCardsInGame(), validDefined.split(","), hostCard.getController(), hostCard, sa);
} else if (defined.startsWith("Valid")) {
String[] s = defined.split(" ");
String zone = s[0].substring("Valid".length());
String validDefined = s[1];
list = CardLists.getValidCards(game.getCardsIn(ZoneType.smartValueOf(zone)), validDefined.split(","), hostCard.getController(), hostCard, sa);
}
if (list != null) { if (list != null) {
cards.addAll(list); cards.addAll(list);
} }
@@ -421,7 +425,7 @@ public class AbilityUtils {
private static Card findEffectRoot(Card startCard) { private static Card findEffectRoot(Card startCard) {
Card cc = startCard.getEffectSource(); Card cc = startCard.getEffectSource();
if (cc != null) { if (cc != null) {
if (cc.isEmblem() || cc.getType().hasSubtype("Effect")) { if (cc.isImmutable()) {
return findEffectRoot(cc); return findEffectRoot(cc);
} }
return cc; return cc;

View File

@@ -13,7 +13,6 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Table; import com.google.common.collect.Table;
import forge.GameCommand; import forge.GameCommand;
import forge.card.CardType;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.game.Game; import forge.game.Game;
import forge.game.GameEntity; import forge.game.GameEntity;
@@ -457,25 +456,19 @@ public abstract class SpellAbilityEffect {
final Card eff = new Card(game.nextCardId(), game); final Card eff = new Card(game.nextCardId(), game);
eff.setTimestamp(game.getNextTimestamp()); eff.setTimestamp(game.getNextTimestamp());
eff.setName(name); eff.setName(name);
eff.setColor(hostCard.determineColor().getColor());
// if name includes emblem then it should be one // if name includes emblem then it should be one
eff.addType(name.startsWith("Emblem") ? "Emblem" : "Effect"); if (name.startsWith("Emblem")) {
// add Planeswalker types into Emblem for fun eff.setEmblem(true);
if (name.startsWith("Emblem") && hostCard.isPlaneswalker()) { // Emblem needs to be colorless
for (final String type : hostCard.getType().getSubtypes()) { eff.setColor(MagicColor.COLORLESS);
if (CardType.isAPlaneswalkerType(type)) {
eff.addType(type);
}
}
} }
eff.setOwner(controller); eff.setOwner(controller);
eff.setSVars(sa.getSVars()); eff.setSVars(sa.getSVars());
eff.setImageKey(image); eff.setImageKey(image);
if (eff.getType().hasType(CardType.CoreType.Emblem)) {
eff.setColor(MagicColor.COLORLESS);
} else {
eff.setColor(hostCard.determineColor().getColor());
}
eff.setImmutable(true); eff.setImmutable(true);
eff.setEffectSource(sa); eff.setEffectSource(sa);

View File

@@ -190,11 +190,6 @@ public class AnimateEffect extends AnimateEffectBase {
} }
} }
// Restore immutable to effect
if (sa.hasParam("Immutable")) {
c.setImmutable(true);
}
game.fireEvent(new GameEventCardStatsChanged(c)); game.fireEvent(new GameEventCardStatsChanged(c));
} }

View File

@@ -12,7 +12,6 @@ public class DetachedCardEffect extends Card {
card = card0; card = card0;
setName(name0); setName(name0);
addType("Effect");
setOwner(card0.getOwner()); setOwner(card0.getOwner());
setImmutable(true); setImmutable(true);

View File

@@ -140,10 +140,6 @@ public class EffectEffect extends SpellAbilityEffect {
final Card eff = createEffect(sa, controller, name, image); final Card eff = createEffect(sa, controller, name, image);
eff.setSetCode(sa.getHostCard().getSetCode()); eff.setSetCode(sa.getHostCard().getSetCode());
eff.setRarity(sa.getHostCard().getRarity()); eff.setRarity(sa.getHostCard().getRarity());
// For Raging River effect to add attacker "left" or "right" pile later
if (sa.hasParam("Mutable")) {
eff.setImmutable(false);
}
// Abilities and triggers work the same as they do for Token // Abilities and triggers work the same as they do for Token
// Grant abilities // Grant abilities

View File

@@ -37,7 +37,7 @@ public class RegenerationEffect extends SpellAbilityEffect {
// Play the Regen sound // Play the Regen sound
game.fireEvent(new GameEventCardRegenerated()); game.fireEvent(new GameEventCardRegenerated());
if (host.getType().hasStringType("Effect")) { if (host.isImmutable()) {
c.subtractShield(host); c.subtractShield(host);
host.removeRemembered(c); host.removeRemembered(c);
} }

View File

@@ -47,7 +47,7 @@ public class ReplaceDamageEffect extends SpellAbilityEffect {
prevent -= n; prevent -= n;
if (!StringUtils.isNumeric(varValue) && card.getSVar(varValue).startsWith("Number$")) { if (!StringUtils.isNumeric(varValue) && card.getSVar(varValue).startsWith("Number$")) {
if (card.getType().hasStringType("Effect") && prevent <= 0) { if (card.isImmutable() && prevent <= 0) {
game.getAction().exile(card, null); game.getAction().exile(card, null);
} else { } else {
card.setSVar(varValue, "Number$" + prevent); card.setSVar(varValue, "Number$" + prevent);

View File

@@ -45,7 +45,7 @@ public class ReplaceSplitDamageEffect extends SpellAbilityEffect {
dmg -= n; dmg -= n;
prevent -= n; prevent -= n;
if (card.getType().hasStringType("Effect") && prevent <= 0) { if (card.isImmutable() && prevent <= 0) {
game.getAction().exile(card, null); game.getAction().exile(card, null);
} else if (!StringUtils.isNumeric(varValue)) { } else if (!StringUtils.isNumeric(varValue)) {
sa.setSVar(varValue, "Number$" + prevent); sa.setSVar(varValue, "Number$" + prevent);

View File

@@ -264,6 +264,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
// for Vanguard / Manapool / Emblems etc. // for Vanguard / Manapool / Emblems etc.
private boolean isImmutable = false; private boolean isImmutable = false;
private boolean isEmblem = false;
private int exertThisTurn = 0; private int exertThisTurn = 0;
private PlayerCollection exertedByPlayer = new PlayerCollection(); private PlayerCollection exertedByPlayer = new PlayerCollection();
@@ -4598,15 +4599,13 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
} }
public final boolean isPermanent() { public final boolean isPermanent() {
return !isImmutable && (isInZone(ZoneType.Battlefield) || getType().isPermanent()); return !isImmutable() && (isInZone(ZoneType.Battlefield) || getType().isPermanent());
} }
public final boolean isSpell() { public final boolean isSpell() {
return (isInstant() || isSorcery() || (isAura() && !isInZone((ZoneType.Battlefield)))); return (isInstant() || isSorcery() || (isAura() && !isInZone((ZoneType.Battlefield))));
} }
public final boolean isEmblem() { return getType().isEmblem(); }
public final boolean isLand() { return getType().isLand(); } public final boolean isLand() { return getType().isLand(); }
public final boolean isBasicLand() { return getType().isBasicLand(); } public final boolean isBasicLand() { return getType().isBasicLand(); }
public final boolean isSnow() { return getType().isSnow(); } public final boolean isSnow() { return getType().isSnow(); }
@@ -4865,11 +4864,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
// Takes one argument like Permanent.Blue+withFlying // Takes one argument like Permanent.Blue+withFlying
@Override @Override
public final boolean isValid(final String restriction, final Player sourceController, final Card source, CardTraitBase spellAbility) { public final boolean isValid(final String restriction, final Player sourceController, final Card source, CardTraitBase spellAbility) {
if (isImmutable() && source != null && !source.isRemembered(this) &&
!(restriction.startsWith("Emblem") || restriction.startsWith("Effect"))) { // special case exclusion
return false;
}
// Inclusive restrictions are Card types // Inclusive restrictions are Card types
final String[] incR = restriction.split("\\.", 2); final String[] incR = restriction.split("\\.", 2);
@@ -4879,14 +4873,27 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
incR[0] = incR[0].substring(1); // consume negation sign incR[0] = incR[0].substring(1); // consume negation sign
} }
if (incR[0].equals("Spell") && !isSpell()) { if (incR[0].equals("Spell")) {
if (!isSpell()) {
return testFailed; return testFailed;
} }
if (incR[0].equals("Permanent") && !isPermanent()) { } else if (incR[0].equals("Permanent")) {
if (!isPermanent()) {
return testFailed; return testFailed;
} }
if (!incR[0].equals("card") && !incR[0].equals("Card") && !incR[0].equals("Spell") } else if (incR[0].equals("Effect")) {
&& !incR[0].equals("Permanent") && !getType().hasStringType(incR[0])) { if (!isImmutable()) {
return testFailed;
}
} else if (incR[0].equals("Emblem")) {
if (!isEmblem()) {
return testFailed;
}
} else if (incR[0].equals("card") || incR[0].equals("Card")) {
if (isImmutable()) {
return testFailed;
}
} else if (!getType().hasStringType(incR[0])) {
return testFailed; // Check for wrong type return testFailed; // Check for wrong type
} }
@@ -4916,6 +4923,15 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
} }
public final void setImmutable(final boolean isImmutable0) { public final void setImmutable(final boolean isImmutable0) {
isImmutable = isImmutable0; isImmutable = isImmutable0;
view.updateImmutable(this);
}
public final boolean isEmblem() {
return isEmblem;
}
public final void setEmblem(final boolean isEmblem0) {
isEmblem = isEmblem0;
view.updateEmblem(this);
} }
/* /*

View File

@@ -357,7 +357,7 @@ public class CardProperty {
return false; return false;
} }
} else if (property.equals("EffectSource")) { } else if (property.equals("EffectSource")) {
if (!source.isEmblem() && !source.getType().hasSubtype("Effect")) { if (!source.isImmutable()) {
return false; return false;
} }

View File

@@ -242,6 +242,7 @@ public final class CardUtil {
newCopy.setToken(in.isToken()); newCopy.setToken(in.isToken());
newCopy.setCopiedSpell(in.isCopiedSpell()); newCopy.setCopiedSpell(in.isCopiedSpell());
newCopy.setImmutable(in.isImmutable()); newCopy.setImmutable(in.isImmutable());
newCopy.setEmblem(in.isEmblem());
// lock in the current P/T // lock in the current P/T
newCopy.setBasePower(in.getCurrentPower()); newCopy.setBasePower(in.getCurrentPower());

View File

@@ -233,6 +233,20 @@ public class CardView extends GameEntityView {
set(TrackableProperty.Token, c.isToken()); set(TrackableProperty.Token, c.isToken());
} }
public boolean isImmutable() {
return get(TrackableProperty.IsImmutable);
}
public void updateImmutable(Card c) {
set(TrackableProperty.IsImmutable, c.isImmutable());
}
public boolean isEmblem() {
return get(TrackableProperty.IsEmblem);
}
public void updateEmblem(Card c) {
set(TrackableProperty.IsEmblem, c.isEmblem());
}
public boolean isTokenCard() { return get(TrackableProperty.TokenCard); } public boolean isTokenCard() { return get(TrackableProperty.TokenCard); }
void updateTokenCard(Card c) { set(TrackableProperty.TokenCard, c.isTokenCard()); } void updateTokenCard(Card c) { set(TrackableProperty.TokenCard, c.isTokenCard()); }

View File

@@ -3176,6 +3176,7 @@ public class Player extends GameEntity implements Comparable<Player> {
if (monarchEffect == null) { if (monarchEffect == null) {
monarchEffect = new Card(game.nextCardId(), null, game); monarchEffect = new Card(game.nextCardId(), null, game);
monarchEffect.setOwner(this); monarchEffect.setOwner(this);
monarchEffect.setImmutable(true);
if (set != null) { if (set != null) {
monarchEffect.setImageKey("t:monarch_" + set.toLowerCase()); monarchEffect.setImageKey("t:monarch_" + set.toLowerCase());
monarchEffect.setSetCode(set); monarchEffect.setSetCode(set);
@@ -3183,7 +3184,6 @@ public class Player extends GameEntity implements Comparable<Player> {
monarchEffect.setImageKey("t:monarch"); monarchEffect.setImageKey("t:monarch");
} }
monarchEffect.setName("The Monarch"); monarchEffect.setName("The Monarch");
monarchEffect.addType("Effect");
{ {
final String drawTrig = "Mode$ Phase | Phase$ End of Turn | TriggerZones$ Command | " + final String drawTrig = "Mode$ Phase | Phase$ End of Turn | TriggerZones$ Command | " +
@@ -3280,8 +3280,7 @@ public class Player extends GameEntity implements Comparable<Player> {
blessingEffect.setOwner(this); blessingEffect.setOwner(this);
blessingEffect.setImageKey("t:blessing"); blessingEffect.setImageKey("t:blessing");
blessingEffect.setName("City's Blessing"); blessingEffect.setName("City's Blessing");
blessingEffect.addType("Effect"); blessingEffect.setImmutable(true);
blessingEffect.updateStateForView(); blessingEffect.updateStateForView();
@@ -3353,7 +3352,6 @@ public class Player extends GameEntity implements Comparable<Player> {
keywordEffect.setOwner(this); keywordEffect.setOwner(this);
keywordEffect.setName("Keyword Effects"); keywordEffect.setName("Keyword Effects");
keywordEffect.setImageKey(ImageKeys.HIDDEN_CARD); keywordEffect.setImageKey(ImageKeys.HIDDEN_CARD);
keywordEffect.addType("Effect");
keywordEffect.updateStateForView(); keywordEffect.updateStateForView();

View File

@@ -95,8 +95,7 @@ public class LandAbility extends Ability {
Card source = sta.getHostCard(); Card source = sta.getHostCard();
if (!source.equals(getHostCard())) { if (!source.equals(getHostCard())) {
sb.append(" by "); sb.append(" by ");
if ((source.isEmblem() || source.getType().hasSubtype("Effect")) if (source.isImmutable() && source.getEffectSource() != null) {
&& source.getEffectSource() != null) {
sb.append(source.getEffectSource()); sb.append(source.getEffectSource());
} else { } else {
sb.append(source); sb.append(source);

View File

@@ -24,6 +24,9 @@ public enum TrackableProperty {
Controller(TrackableTypes.PlayerViewType), Controller(TrackableTypes.PlayerViewType),
Zone(TrackableTypes.EnumType(ZoneType.class)), Zone(TrackableTypes.EnumType(ZoneType.class)),
IsImmutable(TrackableTypes.BooleanType),
IsEmblem(TrackableTypes.BooleanType),
Flipped(TrackableTypes.BooleanType), Flipped(TrackableTypes.BooleanType),
Facedown(TrackableTypes.BooleanType), Facedown(TrackableTypes.BooleanType),
Foretold(TrackableTypes.BooleanType), Foretold(TrackableTypes.BooleanType),

View File

@@ -311,7 +311,7 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl
final CardStateView state = getCard().getCurrentState(); final CardStateView state = getCard().getCurrentState();
final CardEdition ed = FModel.getMagicDb().getEditions().get(state.getSetCode()); final CardEdition ed = FModel.getMagicDb().getEditions().get(state.getSetCode());
boolean colorIsSet = false; boolean colorIsSet = false;
if (state.getType().isEmblem() || state.getType().hasStringType("Effect")) { if (getCard().isImmutable()) {
// Effects are drawn with orange border // Effects are drawn with orange border
g2d.setColor(Color.ORANGE); g2d.setColor(Color.ORANGE);
colorIsSet = true; colorIsSet = true;

View File

@@ -362,8 +362,7 @@ public class CardImageRenderer {
drawDetails(g, card, gameView, altState, x, y, w, h); drawDetails(g, card, gameView, altState, x, y, w, h);
return; return;
} }
if(card.isToken() && card.getCurrentState().getType().hasSubtype("Effect") if(card.isImmutable() && FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DISABLE_IMAGES_EFFECT_CARDS)){
&& FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DISABLE_IMAGES_EFFECT_CARDS)){
drawDetails(g, card, gameView, altState, x, y, w, h); drawDetails(g, card, gameView, altState, x, y, w, h);
return; return;
} }

View File

@@ -5,7 +5,7 @@ PT:3/4
T:Mode$ Phase | Phase$ EndCombat | Execute$ TrigCounter | TriggerZones$ Battlefield | TriggerDescription$ At end of combat, put a paralyzation counter on each creature blocking or blocked by CARDNAME and tap those creatures. Each of those creatures doesn't untap during its controller's untap step for as long as it has a paralyzation counter on it. Each of those creatures gains "{4}: Remove a paralyzation counter from this creature." T:Mode$ Phase | Phase$ EndCombat | Execute$ TrigCounter | TriggerZones$ Battlefield | TriggerDescription$ At end of combat, put a paralyzation counter on each creature blocking or blocked by CARDNAME and tap those creatures. Each of those creatures doesn't untap during its controller's untap step for as long as it has a paralyzation counter on it. Each of those creatures gains "{4}: Remove a paralyzation counter from this creature."
SVar:TrigCounter:DB$ PutCounterAll | CounterType$ PARALYZATION | CounterNum$ 1 | ValidCards$ Creature.blockedBySource,Creature.blockingSource | SubAbility$ DBTap SVar:TrigCounter:DB$ PutCounterAll | CounterType$ PARALYZATION | CounterNum$ 1 | ValidCards$ Creature.blockedBySource,Creature.blockingSource | SubAbility$ DBTap
SVar:DBTap:DB$ TapAll | ValidCards$ Creature.blockedBySource,Creature.blockingSource | SubAbility$ DBEffect SVar:DBTap:DB$ TapAll | ValidCards$ Creature.blockedBySource,Creature.blockingSource | SubAbility$ DBEffect
SVar:DBEffect:DB$ Effect | RememberObjects$ Valid Creature.blockedBySource,Valid Creature.blockingSource | StaticAbilities$ DontUntap | Duration$ Permanent | ConditionPresent$ Creature.blockedBySource,Creature.blockingSource | SubAbility$ DBAnimate | ForgetOnMoved$ Battlefield | ForgetCounter$ PARALYZATION SVar:DBEffect:DB$ Effect | RememberObjects$ Valid Creature.blockedBySource,Creature.blockingSource | StaticAbilities$ DontUntap | Duration$ Permanent | ConditionPresent$ Creature.blockedBySource,Creature.blockingSource | SubAbility$ DBAnimate | ForgetOnMoved$ Battlefield | ForgetCounter$ PARALYZATION
SVar:DBAnimate:DB$ AnimateAll | ValidCards$ Creature.blockedBySource,Creature.blockingSource | Abilities$ ABRemoveCounter | Duration$ Permanent SVar:DBAnimate:DB$ AnimateAll | ValidCards$ Creature.blockedBySource,Creature.blockingSource | Abilities$ ABRemoveCounter | Duration$ Permanent
SVar:ABRemoveCounter:AB$ RemoveCounter | Defined$ Self | Cost$ 4 | CounterType$ PARALYZATION | CounterNum$ 1 | SpellDescription$ Remove a paralyzation counter from this creature. SVar:ABRemoveCounter:AB$ RemoveCounter | Defined$ Self | Cost$ 4 | CounterType$ PARALYZATION | CounterNum$ 1 | SpellDescription$ Remove a paralyzation counter from this creature.
SVar:DontUntap:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Card.IsRemembered | AddHiddenKeyword$ CARDNAME doesn't untap during your untap step. | Description$ Each of those creatures doesn't untap during its controller's untap step for as long as it has a paralyzation counter on it. SVar:DontUntap:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Card.IsRemembered | AddHiddenKeyword$ CARDNAME doesn't untap during your untap step. | Description$ Each of those creatures doesn't untap during its controller's untap step for as long as it has a paralyzation counter on it.

View File

@@ -5,5 +5,5 @@ PT:3/3
K:First Strike K:First Strike
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigExile | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, exile it and return to the battlefield all artifact and creature cards in your graveyard that were put there from the battlefield this turn. T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigExile | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, exile it and return to the battlefield all artifact and creature cards in your graveyard that were put there from the battlefield this turn.
SVar:TrigExile:DB$ ChangeZone | Defined$ TriggeredNewCardLKICopy | Origin$ Graveyard | Destination$ Exile | SubAbility$ DBReturn SVar:TrigExile:DB$ ChangeZone | Defined$ TriggeredNewCardLKICopy | Origin$ Graveyard | Destination$ Exile | SubAbility$ DBReturn
SVar:DBReturn:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | Defined$ ValidGraveyard Artifact,Creature.YouOwn+ThisTurnEnteredFrom_Battlefield SVar:DBReturn:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | Defined$ ValidGraveyard Artifact.YouOwn+ThisTurnEnteredFrom_Battlefield,Creature.YouOwn+ThisTurnEnteredFrom_Battlefield
Oracle:First strike\nWhen Gerrard, Weatherlight Hero dies, exile it and return to the battlefield all artifact and creature cards in your graveyard that were put there from the battlefield this turn. Oracle:First strike\nWhen Gerrard, Weatherlight Hero dies, exile it and return to the battlefield all artifact and creature cards in your graveyard that were put there from the battlefield this turn.

View File

@@ -1,17 +1,16 @@
Name:Plague of Vermin Name:Plague of Vermin
ManaCost:6 B ManaCost:6 B
Types:Sorcery Types:Sorcery
A:SP$ Effect | Cost$ 6 B | Name$ Plague of Vermin Life Paid | EffectOwner$ Player | ImprintOnHost$ True | Mutable$ True | Duration$ Permanent | SubAbility$ DBRepeat | StackDescription$ SpellDescription | SpellDescription$ Starting with you, each player may pay any amount of life. Repeat this process until no one pays life. Each player creates a 1/1 black Rat creature token for each 1 life they paid this way. A:SP$ Effect | Cost$ 6 B | Name$ Plague of Vermin Life Paid | EffectOwner$ Player | ImprintOnHost$ True | Duration$ Permanent | SubAbility$ DBRepeat | StackDescription$ SpellDescription | SpellDescription$ Starting with you, each player may pay any amount of life. Repeat this process until no one pays life. Each player creates a 1/1 black Rat creature token for each 1 life they paid this way.
SVar:DBRepeat:DB$ Repeat | RepeatSubAbility$ DBResetCheck | RepeatCheckSVar$ NumPlayerGiveup | RepeatSVarCompare$ LTTotalPlayer | SubAbility$ DBRepeatToken SVar:DBRepeat:DB$ Repeat | RepeatSubAbility$ DBResetCheck | RepeatCheckSVar$ NumPlayerGiveup | RepeatSVarCompare$ LTTotalPlayer | SubAbility$ DBRepeatToken
SVar:DBResetCheck:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ Number | Expression$ 0 | SubAbility$ DBRepeatChoice SVar:DBResetCheck:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ Number | Expression$ 0 | SubAbility$ DBRepeatChoice
SVar:DBRepeatChoice:DB$ RepeatEach | StartingWithActivator$ True | RepeatSubAbility$ DBChoice | RepeatPlayers$ Player SVar:DBRepeatChoice:DB$ RepeatEach | StartingWithActivator$ True | RepeatSubAbility$ DBChoice | RepeatPlayers$ Player
SVar:DBChoice:DB$ ChooseNumber | Defined$ Player.IsRemembered | Max$ LifeTotal | AILogic$ Vermin | ListTitle$ Pay Any Amount of Life | SubAbility$ DBCheckPaid SVar:DBChoice:DB$ ChooseNumber | Defined$ Player.IsRemembered | Max$ LifeTotal | AILogic$ Vermin | ListTitle$ Pay Any Amount of Life | SubAbility$ DBCheckPaid
SVar:DBCheckPaid:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ CountSVar | Expression$ NumPlayerGiveup/Plus.1 | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ0 | SubAbility$ DBStore SVar:DBCheckPaid:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ CountSVar | Expression$ NumPlayerGiveup/Plus.1 | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ0 | SubAbility$ DBStore
SVar:DBStore:DB$ PutCounter | Defined$ Imprinted.namedPlague of Vermin Life Paid+OwnedBy Player.IsRemembered | CounterNum$ X | Placer$ Player.IsRemembered | CounterType$ PLAGUE | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | UnlessCost$ PayLife<X> | UnlessPayer$ Player.IsRemembered | UnlessSwitched$ True | UnlessResolveSubs$ WhenNotPaid | SubAbility$ DBGiveUp | SpellDescription$ You may pay any amount of life. SVar:DBStore:DB$ PutCounter | Defined$ ValidCommand Effect.namedPlague of Vermin Life Paid+OwnedBy Player.IsRemembered | CounterNum$ X | Placer$ Player.IsRemembered | CounterType$ PLAGUE | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | UnlessCost$ PayLife<X> | UnlessPayer$ Player.IsRemembered | UnlessSwitched$ True | UnlessResolveSubs$ WhenNotPaid | SubAbility$ DBGiveUp | SpellDescription$ You may pay any amount of life.
SVar:DBGiveUp:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ CountSVar | Expression$ NumPlayerGiveup/Plus.1 | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 SVar:DBGiveUp:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ CountSVar | Expression$ NumPlayerGiveup/Plus.1 | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1
SVar:DBRepeatToken:DB$ RepeatEach | StartingWithActivator$ True | RepeatSubAbility$ DBToken | RepeatPlayers$ Player | SubAbility$ DBFinalReset SVar:DBRepeatToken:DB$ RepeatEach | StartingWithActivator$ True | RepeatSubAbility$ DBToken | RepeatPlayers$ Player | SubAbility$ DBFinalReset
SVar:DBToken:DB$ Token | TokenAmount$ LifePaidAmount | TokenScript$ b_1_1_rat | TokenOwner$ Player.IsRemembered | StackDescription$ None | SubAbility$ DBRestoreImmutable SVar:DBToken:DB$ Token | TokenAmount$ LifePaidAmount | TokenScript$ b_1_1_rat | TokenOwner$ Player.IsRemembered | StackDescription$ None
SVar:DBRestoreImmutable:DB$ Animate | Defined$ Imprinted.namedPlague of Vermin Life Paid+OwnedBy Player.IsRemembered | Duration$ Permanent | Immutable$ True
SVar:DBFinalReset:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ Number | Expression$ 0 | SubAbility$ DBExileEffect SVar:DBFinalReset:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ Number | Expression$ 0 | SubAbility$ DBExileEffect
SVar:DBExileEffect:DB$ ChangeZone | Defined$ Imprinted | Origin$ Command | Destination$ Exile | SubAbility$ DBCleanup SVar:DBExileEffect:DB$ ChangeZone | Defined$ Imprinted | Origin$ Command | Destination$ Exile | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True

View File

@@ -3,16 +3,16 @@ ManaCost:R R
Types:Enchantment Types:Enchantment
T:Mode$ AttackersDeclared | AttackingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigRepeatDefender | TriggerDescription$ Whenever one or more creatures you control attack, each defending player divides all creatures without flying they control into a "left" pile and a "right" pile. Then, for each attacking creature you control, choose "left" or "right." That creature can't be blocked this combat except by creatures with flying and creatures in a pile with the chosen label. T:Mode$ AttackersDeclared | AttackingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigRepeatDefender | TriggerDescription$ Whenever one or more creatures you control attack, each defending player divides all creatures without flying they control into a "left" pile and a "right" pile. Then, for each attacking creature you control, choose "left" or "right." That creature can't be blocked this combat except by creatures with flying and creatures in a pile with the chosen label.
SVar:TrigRepeatDefender:DB$ RepeatEach | RepeatPlayers$ TriggeredAttackedTarget | RepeatSubAbility$ DBDefLeftEffect | SubAbility$ DBAtkLeftRight SVar:TrigRepeatDefender:DB$ RepeatEach | RepeatPlayers$ TriggeredAttackedTarget | RepeatSubAbility$ DBDefLeftEffect | SubAbility$ DBAtkLeftRight
SVar:DBDefLeftEffect:DB$ Effect | EffectOwner$ Remembered | Name$ Raging River Left | StaticAbilities$ DBCantBlock | ImprintOnHost$ True | Mutable$ True | Duration$ UntilEndOfCombat | SubAbility$ DBDefRightEffect SVar:DBDefLeftEffect:DB$ Effect | EffectOwner$ Remembered | Name$ Raging River Left | StaticAbilities$ DBCantBlock | ImprintOnHost$ True | Duration$ UntilEndOfCombat | SubAbility$ DBDefRightEffect
SVar:DBDefRightEffect:DB$ Effect | EffectOwner$ Remembered | Name$ Raging River Right | StaticAbilities$ DBCantBlock | ImprintOnHost$ True | Mutable$ True | Duration$ UntilEndOfCombat | SubAbility$ DBDefLeftRight SVar:DBDefRightEffect:DB$ Effect | EffectOwner$ Remembered | Name$ Raging River Right | StaticAbilities$ DBCantBlock | ImprintOnHost$ True | Duration$ UntilEndOfCombat | SubAbility$ DBDefLeftRight
SVar:DBCantBlock:Mode$ CantBlockBy | ValidAttacker$ Creature.IsRemembered | ValidBlocker$ Creature.withoutFlying+IsNotImprinted+YouCtrl | EffectZone$ Command SVar:DBCantBlock:Mode$ CantBlockBy | ValidAttacker$ Creature.IsRemembered | ValidBlocker$ Creature.withoutFlying+IsNotImprinted+YouCtrl | EffectZone$ Command
SVar:DBDefLeftRight:DB$ TwoPiles | Defined$ Remembered | Separator$ Remembered | ValidCards$ Creature.withoutFlying+RememberedPlayerCtrl | Zone$ Battlefield | LeftRightPile$ True | ChosenPile$ DBDefLeftPile | UnchosenPile$ DBDefRightPile | AILogic$ Random | SubAbility$ DBClearImprinted SVar:DBDefLeftRight:DB$ TwoPiles | Defined$ Remembered | Separator$ Remembered | ValidCards$ Creature.withoutFlying+RememberedPlayerCtrl | Zone$ Battlefield | LeftRightPile$ True | ChosenPile$ DBDefLeftPile | UnchosenPile$ DBDefRightPile | AILogic$ Random | SubAbility$ DBClearImprinted
SVar:DBDefLeftPile:DB$ Animate | Defined$ Imprinted.namedRaging River Left | ImprintCards$ Remembered | Duration$ Permanent | SubAbility$ DBLeftPump SVar:DBDefLeftPile:DB$ Animate | Defined$ ValidCommand Effect.namedRaging River Left+IsImprinted | ImprintCards$ Remembered | Duration$ Permanent | SubAbility$ DBLeftPump
SVar:DBDefRightPile:DB$ Animate | Defined$ Imprinted.namedRaging River Right | ImprintCards$ Remembered | Duration$ Permanent | SubAbility$ DBRightPump SVar:DBDefRightPile:DB$ Animate | Defined$ ValidCommand Effect.namedRaging River Right+IsImprinted | ImprintCards$ Remembered | Duration$ Permanent | SubAbility$ DBRightPump
SVar:DBClearImprinted:DB$ Cleanup | ClearImprinted$ True SVar:DBClearImprinted:DB$ Cleanup | ClearImprinted$ True
SVar:DBAtkLeftRight:DB$ TwoPiles | Defined$ You | Separator$ You | ValidCards$ Creature.attacking+YouCtrl | Zone$ Battlefield | LeftRightPile$ True | ChosenPile$ DBAtkLeftPile | UnchosenPile$ DBAtkRightPile | AILogic$ Random | SubAbility$ DBCleanup SVar:DBAtkLeftRight:DB$ TwoPiles | Defined$ You | Separator$ You | ValidCards$ Creature.attacking+YouCtrl | Zone$ Battlefield | LeftRightPile$ True | ChosenPile$ DBAtkLeftPile | UnchosenPile$ DBAtkRightPile | AILogic$ Random | SubAbility$ DBCleanup
SVar:DBAtkLeftPile:DB$ Animate | Defined$ ValidCommand Effect.namedRaging River Left | RememberObjects$ RememberedCard | Duration$ Permanent | Immutable$ True | SubAbility$ DBLeftPump SVar:DBAtkLeftPile:DB$ Animate | Defined$ ValidCommand Effect.namedRaging River Left | RememberObjects$ RememberedCard | Duration$ Permanent | SubAbility$ DBLeftPump
SVar:DBAtkRightPile:DB$ Animate | Defined$ ValidCommand Effect.namedRaging River Right | RememberObjects$ RememberedCard | Duration$ Permanent | Immutable$ True | SubAbility$ DBRightPump SVar:DBAtkRightPile:DB$ Animate | Defined$ ValidCommand Effect.namedRaging River Right | RememberObjects$ RememberedCard | Duration$ Permanent | SubAbility$ DBRightPump
SVar:DBLeftPump:DB$ Pump | Defined$ Remembered | KW$ "Left" pile | Duration$ UntilEndOfCombat SVar:DBLeftPump:DB$ Pump | Defined$ Remembered | KW$ "Left" pile | Duration$ UntilEndOfCombat
SVar:DBRightPump:DB$ Pump | Defined$ Remembered | KW$ "Right" pile | Duration$ UntilEndOfCombat SVar:DBRightPump:DB$ Pump | Defined$ Remembered | KW$ "Right" pile | Duration$ UntilEndOfCombat
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True

View File

@@ -1,5 +1,5 @@
Name:Second Sunrise Name:Second Sunrise
ManaCost:1 W W ManaCost:1 W W
Types:Instant Types:Instant
A:SP$ChangeZone | Cost$ 1 W W | Origin$ Graveyard | Destination$ Battlefield | Defined$ ValidGraveyard Artifact,Creature,Enchantment,Land.ThisTurnEnteredFrom_Battlefield | SpellDescription$ Each player returns to the battlefield all artifact, creature, enchantment, and land cards in their graveyard that were put there from the battlefield this turn. A:SP$ChangeZone | Cost$ 1 W W | Origin$ Graveyard | Destination$ Battlefield | Defined$ ValidGraveyard Artifact.ThisTurnEnteredFrom_Battlefield,Creature.ThisTurnEnteredFrom_Battlefield,Enchantment.ThisTurnEnteredFrom_Battlefield,Land.ThisTurnEnteredFrom_Battlefield | SpellDescription$ Each player returns to the battlefield all artifact, creature, enchantment, and land cards in their graveyard that were put there from the battlefield this turn.
Oracle:Each player returns to the battlefield all artifact, creature, enchantment, and land cards in their graveyard that were put there from the battlefield this turn. Oracle:Each player returns to the battlefield all artifact, creature, enchantment, and land cards in their graveyard that were put there from the battlefield this turn.

View File

@@ -121,7 +121,7 @@ public class Puzzle extends GameState implements InventoryItem, Comparable<Puzzl
goalCard.setOwner(human); goalCard.setOwner(human);
goalCard.setImageKey("t:puzzle"); goalCard.setImageKey("t:puzzle");
goalCard.setName("Puzzle Goal"); goalCard.setName("Puzzle Goal");
goalCard.addType("Effect"); goalCard.setImmutable(true);
goalCard.setOracleText(getGoalDescription()); goalCard.setOracleText(getGoalDescription());
int turnCorr = 0; int turnCorr = 0;

View File

@@ -221,7 +221,7 @@ public class CardDetailUtil {
String curColors = ""; String curColors = "";
// do not show current colors for temp effect cards, emblems and the like // do not show current colors for temp effect cards, emblems and the like
if (state.getType().isEmblem() || state.getType().hasSubtype("Effect")) { if (state.getCard().isImmutable()) {
return ""; return "";
} }
@@ -275,16 +275,14 @@ public class CardDetailUtil {
// Token // Token
if (card.isToken()) { if (card.isToken()) {
if(card.getCurrentState().getType().hasSubtype("Effect"))
area.append("Effect");
else if(card.getCurrentState().getType().isEmblem())
area.append("Emblem");
else
area.append("Token"); area.append("Token");
} else if (card.isTokenCard()) { } else if (card.isTokenCard()) {
area.append("Token card"); area.append("Token card");
} else if(card.isEmblem()) {
area.append("Emblem");
} else if(card.isImmutable()) {
area.append("Effect");
} }
// card text // card text
if (area.length() != 0) { if (area.length() != 0) {
area.append("\n"); area.append("\n");