Merge branch 'tokenCardText' into 'master'

Token card text

Closes #716

See merge request core-developers/forge!961
This commit is contained in:
Michael Kamensky
2018-10-02 07:18:45 +00:00
32 changed files with 408 additions and 46 deletions

View File

@@ -188,6 +188,21 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
return supertypes.remove(st);
}
public boolean remove(final String str) {
boolean changed = false;
if (CardType.isASupertype(str) && supertypes.remove(stringToSupertype.get(str))) {
changed = true;
} else if (CardType.isACardType(str) && coreTypes.remove(stringToCoreType.get(str))) {
changed = true;
} else if (subtypes.remove(str)) {
changed = true;
}
if (changed) {
calculatedType = null;
}
return changed;
}
public boolean setCreatureTypes(Collection<String> ctypes) {
// if it isn't a creature then this has no effect
if (!isCreature() && !isTribal()) {

View File

@@ -46,6 +46,11 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView {
protected Map<String, String> sVars = Maps.newHashMap();
protected Map<String, String> intrinsicChangedTextColors = Maps.newHashMap();
protected Map<String, String> intrinsicChangedTextTypes = Maps.newHashMap();
protected Map<String, String> changedTextColors = Maps.newHashMap();
protected Map<String, String> changedTextTypes = Maps.newHashMap();
/** Keys of descriptive (text) parameters. */
private static final ImmutableList<String> descriptiveKeys = ImmutableList.<String>builder()
.add("Description", "SpellDescription", "StackDescription", "TriggerDescription").build();
@@ -53,6 +58,11 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView {
private static final ImmutableList<String> mutableKeys = ImmutableList.<String>builder()
.add("AddAbility").build();
/**
* Keys that should not changed
*/
private static final ImmutableList<String> noChangeKeys = ImmutableList.<String>builder()
.add("TokenScript", "LegacyImage", "TokenImage").build();
/**
* Sets the temporary.
*
@@ -449,9 +459,15 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView {
}
public void changeText() {
// copy changed text words into card trait there
this.changedTextColors = getHostCard().getChangedTextColorWords();
this.changedTextTypes = getHostCard().getChangedTextTypeWords();
for (final String key : this.mapParams.keySet()) {
final String value = this.originalMapParams.get(key), newValue;
if (descriptiveKeys.contains(key)) {
if (noChangeKeys.contains(key)) {
continue;
} else if (descriptiveKeys.contains(key)) {
// change descriptions differently
newValue = AbilityUtils.applyDescriptionTextChangeEffects(value, this);
} else if (mutableKeys.contains(key)) {
@@ -515,4 +531,53 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView {
public Set<String> getSVars() {
return sVars.keySet();
}
public Map<String, String> getChangedTextColors() {
return _combineChangedMap(intrinsicChangedTextColors, changedTextColors);
}
public Map<String, String> getChangedTextTypes() {
return _combineChangedMap(intrinsicChangedTextTypes, changedTextTypes);
}
private Map<String, String> _combineChangedMap(Map<String, String> input, Map<String, String> output) {
// no need to do something, just return hash
if (input.isEmpty()) {
return output;
}
if (output.isEmpty()) {
return input;
}
// magic combine them
Map<String, String> result = Maps.newHashMap(output);
for (Map.Entry<String, String> e : input.entrySet()) {
String value = e.getValue();
result.put(e.getKey(), output.containsKey(value) ? output.get(value) : value);
}
return result;
}
public void changeTextIntrinsic(Map<String,String> colorMap, Map<String,String> typeMap) {
intrinsicChangedTextColors = colorMap;
intrinsicChangedTextTypes = typeMap;
for (final String key : this.mapParams.keySet()) {
final String value = this.originalMapParams.get(key), newValue;
if (noChangeKeys.contains(key)) {
continue;
} else if (descriptiveKeys.contains(key)) {
// change descriptions differently
newValue = AbilityUtils.applyTextChangeEffects(value, true, colorMap, typeMap);
}else if (this.getHostCard().hasSVar(value)) {
// don't change literal SVar names!
continue;
} else {
newValue = AbilityUtils.applyTextChangeEffects(value, false, colorMap, typeMap);
}
if (newValue != null) {
this.mapParams.put(key, newValue);
}
}
// this does overwrite the original MapParams
this.originalMapParams = Maps.newHashMap(this.mapParams);
}
}

View File

@@ -1724,12 +1724,18 @@ public class AbilityUtils {
}
private static final String applyTextChangeEffects(final String def, final Card card, final boolean isDescriptive) {
return applyTextChangeEffects(def, isDescriptive,
card.getChangedTextColorWords(), card.getChangedTextTypeWords());
}
public static final String applyTextChangeEffects(final String def, final boolean isDescriptive,
Map<String,String> colorMap, Map<String,String> typeMap) {
if (StringUtils.isEmpty(def)) {
return def;
}
String replaced = def;
for (final Entry<String, String> e : card.getChangedTextColorWords().entrySet()) {
for (final Entry<String, String> e : colorMap.entrySet()) {
final String key = e.getKey();
String value;
if (key.equals("Any")) {
@@ -1750,7 +1756,7 @@ public class AbilityUtils {
replaced = replaced.replaceAll("(?<!>)" + key, value);
}
}
for (final Entry<String, String> e : card.getChangedTextTypeWords().entrySet()) {
for (final Entry<String, String> e : typeMap.entrySet()) {
final String key = e.getKey();
final String pkey = CardType.getPluralType(key);
final String pvalue = getReplacedText(pkey, CardType.getPluralType(e.getValue()), isDescriptive);

View File

@@ -3640,6 +3640,12 @@ public class Card extends GameEntity implements Comparable<Card> {
}
}
public final void removeIntrinsicKeyword(final KeywordInterface s) {
if (currentState.removeIntrinsicKeyword(s)) {
currentState.getView().updateKeywords(this, currentState);
}
}
public Collection<KeywordInterface> getExtrinsicKeyword() {
return extrinsicKeyword.getValues();
}

View File

@@ -7,8 +7,6 @@ import java.util.SortedMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import forge.card.CardType;
public final class CardChangedWords {
private final SortedMap<Long, CardChangedWord> map = Maps.newTreeMap();
@@ -68,14 +66,9 @@ public final class CardChangedWords {
// the actual change (b->c)
resultCache.put(ccw.getOriginalWord(), ccw.getNewWord());
// possible plural form
final String singular = CardType.getPluralType(ccw.getOriginalWord());
if (!singular.equals(ccw.getOriginalWord())) {
resultCache.put(singular, ccw.getNewWord());
}
}
// TODO should that be removed?
for (final String key : ImmutableList.copyOf(resultCache.keySet())) {
if (!key.equals("Any")) {
resultCache.put(key.toLowerCase(), resultCache.get(key).toLowerCase());

View File

@@ -231,6 +231,9 @@ public class CardState extends GameObject {
public final boolean removeIntrinsicKeyword(final String s) {
return intrinsicKeywords.remove(s);
}
public final boolean removeIntrinsicKeyword(final KeywordInterface s) {
return intrinsicKeywords.remove(s);
}
public final FCollectionView<SpellAbility> getSpellAbilities() {
FCollection<SpellAbility> newCol = new FCollection<SpellAbility>(manaAbilities);
@@ -554,4 +557,19 @@ public class CardState extends GameObject {
}
}
}
public void changeTextIntrinsic(Map<String,String> colorMap, Map<String,String> typeMap) {
final List<CardTraitBase> allAbs = ImmutableList.<CardTraitBase>builder()
.addAll(manaAbilities)
.addAll(nonManaAbilities)
.addAll(triggers)
.addAll(replacementEffects)
.addAll(staticAbilities)
.build();
for (final CardTraitBase ctb : allAbs) {
if (ctb.isIntrinsic()) {
ctb.changeTextIntrinsic(colorMap, typeMap);
}
}
}
}

View File

@@ -281,6 +281,8 @@ public final class CardUtil {
newCopy.setChangedCardKeywords(in.getChangedCardKeywords());
newCopy.setChangedCardTypes(in.getChangedCardTypesMap());
newCopy.copyChangedTextFrom(in);
newCopy.setMeldedWith(in.getMeldedWith());
newCopy.setTimestamp(in.getTimestamp());

View File

@@ -12,6 +12,7 @@ import forge.game.Game;
import forge.game.card.Card;
import forge.game.card.CardFactory;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardUtil;
import forge.game.keyword.KeywordInterface;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
@@ -20,6 +21,8 @@ import forge.item.PaperToken;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
public class TokenInfo {
final String name;
final String imageName;
@@ -229,10 +232,121 @@ public class TokenInfo {
String edition = host.getSetCode();
PaperToken token = StaticData.instance().getAllTokens().getToken(script, edition);
// TODO add Card Text Change from SpellAbility
if (token != null) {
return Card.fromPaperCard(token, null, game);
final Card result = Card.fromPaperCard(token, null, game);
// update Token with CardTextChanges
Map<String, String> colorMap = sa.getChangedTextColors();
Map<String, String> typeMap = sa.getChangedTextTypes();
if (!colorMap.isEmpty()) {
if (!result.isColorless()) {
// change Token Colors
byte color = CardUtil.getColors(result).getColor();
for (final Map.Entry<String, String> e : colorMap.entrySet()) {
byte v = MagicColor.fromName(e.getValue());
// Any used by Swirl the Mists
if ("Any".equals(e.getKey())) {
for (final byte c : MagicColor.WUBRG) {
// try to replace color flips
if ((color & c) != 0) {
color &= ~c;
color |= v;
}
}
} else {
byte c = MagicColor.fromName(e.getKey());
// try to replace color flips
if ((color & c) != 0) {
color &= ~c;
color |= v;
}
}
}
result.setColor(color);
}
}
if (!typeMap.isEmpty()) {
String oldName = result.getName();
CardType type = new CardType(result.getType());
String joinedName = StringUtils.join(type.getSubtypes(), " ");
final boolean nameGenerated = oldName.equals(joinedName);
boolean typeChanged = false;
if (!Iterables.isEmpty(type.getSubtypes())) {
for (final Map.Entry<String, String> e : typeMap.entrySet()) {
if (type.hasSubtype(e.getKey())) {
type.remove(e.getKey());
type.add(e.getValue());
typeChanged = true;
}
}
}
if (typeChanged) {
result.setType(type);
// update generated Name
if (nameGenerated) {
result.setName(StringUtils.join(type.getSubtypes(), " "));
}
}
}
// replace Intrinsic Keyword
List<KeywordInterface> toRemove = Lists.newArrayList();
List<String> toAdd = Lists.newArrayList();
for (final KeywordInterface k : result.getCurrentState().getIntrinsicKeywords()) {
final String o = k.getOriginal();
// only Modifiable should go there
if (!CardUtil.isKeywordModifiable(o)) {
continue;
}
String r = new String(o);
// replace types
for (final Map.Entry<String, String> e : typeMap.entrySet()) {
final String key = e.getKey();
final String pkey = CardType.getPluralType(key);
final String value = e.getValue();
final String pvalue = CardType.getPluralType(e.getValue());
r = r.replaceAll(pkey, pvalue);
r = r.replaceAll(key, value);
}
// replace color words
for (final Map.Entry<String, String> e : colorMap.entrySet()) {
final String vName = e.getValue();
final String vCaps = StringUtils.capitalize(vName);
final String vLow = vName.toLowerCase();
if ("Any".equals(e.getKey())) {
for (final byte c : MagicColor.WUBRG) {
final String cName = MagicColor.toLongString(c);
final String cNameCaps = StringUtils.capitalize(cName);
final String cNameLow = cName.toLowerCase();
r = r.replaceAll(cNameCaps, vCaps);
r = r.replaceAll(cNameLow, vLow);
}
} else {
final String cName = e.getKey();
final String cNameCaps = StringUtils.capitalize(cName);
final String cNameLow = cName.toLowerCase();
r = r.replaceAll(cNameCaps, vCaps);
r = r.replaceAll(cNameLow, vLow);
}
}
if (!r.equals(o)) {
toRemove.add(k);
toAdd.add(r);
}
}
for (final KeywordInterface k : toRemove) {
result.getCurrentState().removeIntrinsicKeyword(k);
}
result.addIntrinsicKeywords(toAdd);
result.getCurrentState().changeTextIntrinsic(colorMap, typeMap);
return result;
}
return null;

View File

@@ -96,6 +96,10 @@ public class KeywordCollection implements Iterable<String>, Serializable {
return result;
}
public boolean remove(KeywordInterface keyword) {
return map.remove(keyword.getKeyword(), keyword);
}
public boolean removeAll(Iterable<String> keywords) {
boolean result = false;
for (String k : keywords) {

View File

@@ -1709,6 +1709,31 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
}
}
/* (non-Javadoc)
* @see forge.game.CardTraitBase#changeTextIntrinsic(java.util.Map, java.util.Map)
*/
@Override
public void changeTextIntrinsic(Map<String, String> colorMap, Map<String, String> typeMap) {
super.changeTextIntrinsic(colorMap, typeMap);
if (subAbility != null) {
// if the parent of the subability is not this,
// then there might be a loop
if (subAbility.getParent() == this) {
subAbility.changeTextIntrinsic(colorMap, typeMap);
}
}
for (AbilitySub sa : additionalAbilities.values()) {
sa.changeTextIntrinsic(colorMap, typeMap);
}
for (List<AbilitySub> list : additionalAbilityLists.values()) {
for (AbilitySub sa : list) {
sa.changeTextIntrinsic(colorMap, typeMap);
}
}
}
@Override
public void setIntrinsic(boolean i) {
super.setIntrinsic(i);

View File

@@ -169,11 +169,7 @@ public abstract class Trigger extends TriggerReplacementBase {
if (!desc.contains("ABILITY")) {
return desc;
}
SpellAbility sa = getOverridingAbility();
if (sa == null && this.mapParams.containsKey("Execute")) {
sa = AbilityFactory.getAbility(state, this.mapParams.get("Execute"));
setOverridingAbility(sa);
}
SpellAbility sa = ensureAbility();
return replaceAbilityText(desc, sa);
@@ -583,4 +579,48 @@ public abstract class Trigger extends TriggerReplacementBase {
throw new RuntimeException("Trigger : clone() error, " + ex);
}
}
/* (non-Javadoc)
* @see forge.game.CardTraitBase#changeText()
*/
@Override
public void changeText() {
if (!isIntrinsic()) {
return;
}
super.changeText();
ensureAbility();
if (getOverridingAbility() != null) {
getOverridingAbility().changeText();
}
}
/* (non-Javadoc)
* @see forge.game.CardTraitBase#changeTextIntrinsic(java.util.Map, java.util.Map)
*/
@Override
public void changeTextIntrinsic(Map<String, String> colorMap, Map<String, String> typeMap) {
if (!isIntrinsic()) {
return;
}
super.changeTextIntrinsic(colorMap, typeMap);
ensureAbility();
if (getOverridingAbility() != null) {
getOverridingAbility().changeTextIntrinsic(colorMap, typeMap);
}
}
private SpellAbility ensureAbility() {
SpellAbility sa = getOverridingAbility();
if (sa == null && hasParam("Execute")) {
sa = AbilityFactory.getAbility(getHostCard(), getParam("Execute"));
setOverridingAbility(sa);
}
return sa;
}
}

View File

@@ -3,8 +3,7 @@ ManaCost:3 R
Types:Creature Human Shaman
PT:2/3
T:Mode$ Attached | ValidSource$ Aura | ValidTarget$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever an Aura becomes attached to CARDNAME, create a 2/2 red Dragon creature token with flying. It has "{R}: This creature gets +1/+0 until end of turn."
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenName$ Dragon | TokenTypes$ Creature,Dragon | TokenOwner$ You | TokenColors$ Red | TokenPower$ 2 | TokenToughness$ 2 | TokenImage$ r 2 2 dragon M15 | TokenKeywords$ Flying | TokenAbilities$ BroodPump
SVar:BroodPump:AB$ Pump | Cost$ R | NumAtt$ +1 | SpellDescription$ CARDNAME gets +1/+0 until end of turn.
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenOwner$ You | LegacyImage$ r 2 2 dragon M15 | TokenScript$ r_2_2_dragon_flying_firebreathing
SVar:EnchantMe:Multiple
SVar:Picture:http://www.wizards.com/global/images/magic/general/brood_keeper.jpg
Oracle:Whenever an Aura becomes attached to Brood Keeper, create a 2/2 red Dragon creature token with flying. It has "{R}: This creature gets +1/+0 until end of turn."

View File

@@ -4,8 +4,7 @@ Types:Creature Dragon Egg
PT:0/2
K:Defender
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigToken | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, create a 2/2 red Dragon creature token with flying. It has "{R}: This creature gets +1/+0 until end of turn".
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenName$ Dragon | TokenTypes$ Creature,Dragon | TokenOwner$ You | TokenColors$ Red | TokenPower$ 2 | TokenToughness$ 2 | TokenImage$ r 2 2 dragon M14 | TokenKeywords$ Flying | TokenAbilities$ DragonPump
SVar:DragonPump:AB$ Pump | Cost$ R | NumAtt$ +1 | SpellDescription$ CARDNAME gets +1/+0 until end of turn.
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenOwner$ You | LegacyImage$ r 2 2 dragon M14 | TokenScript$ r_2_2_dragon_flying_firebreathing
SVar:SacMe:4
DeckHas:Ability$Token
SVar:Picture:http://www.wizards.com/global/images/magic/general/dragon_egg.jpg

View File

@@ -4,6 +4,6 @@ Types:Creature Horror
PT:7/7
K:Trample
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield, target opponent creates two 3/3 green Centaur creature tokens with protection from black.
SVar:TrigToken:DB$ Token | TokenAmount$ 2 | TokenName$ Centaur | TokenImage$ g 3 3 centaur pro black | TokenTypes$ Creature,Centaur | ValidTgts$ Opponent | TokenOwner$ Targeted | TokenColors$ Green | TokenPower$ 3 | TokenToughness$ 3 | TokenKeywords$ Protection from black
SVar:TrigToken:DB$ Token | TokenAmount$ 2 | TokenScript$ g_3_3_centaur_pro_black | ValidTgts$ Opponent | TokenOwner$ Targeted | LegacyImage$ g 3 3 centaur pro black
SVar:Picture:http://www.wizards.com/global/images/magic/general/hunted_horror.jpg
Oracle:Trample\nWhen Hunted Horror enters the battlefield, target opponent creates two 3/3 green Centaur creature tokens with protection from black.

View File

@@ -5,7 +5,7 @@ PT:5/5
K:Forestwalk
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ Whenever CARDNAME attacks or blocks, create a 2/2 green Cat Warrior creature token with forestwalk.
T:Mode$ Blocks | ValidCard$ Card.Self | Execute$ TrigToken | Secondary$ True | TriggerDescription$ Whenever CARDNAME attacks or blocks, create a 2/2 green Cat Warrior creature token with forestwalk.
SVar:TrigToken:DB$Token | TokenAmount$ 1 | TokenName$ Cat Warrior | TokenTypes$ Creature,Cat,Warrior | TokenOwner$ You | TokenColors$ Green | TokenPower$ 2 | TokenToughness$ 2 | TokenKeywords$ Forestwalk
SVar:TrigToken:DB$Token | TokenAmount$ 1 | TokenOwner$ You | TokenScript$ g_2_2_cat_warrior_forestwalk
SVar:HasAttackEffect:TRUE
SVar:HasBlockEffect:TRUE
SVar:Picture:http://www.wizards.com/global/images/magic/general/jedit_ojanen_of_efrava.jpg

View File

@@ -5,8 +5,7 @@ PT:*/*
S:Mode$ Continuous | EffectZone$ All | CharacteristicDefining$ True | SetPower$ X | SetToughness$ X | Description$ CARDNAMEs power and toughness are each equal to the number of Forests you control.
SVar:X:Count$Valid Forest.YouCtrl
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield, create a green Treefolk Warrior creature token with "This creature's power and toughness are each equal to the number of Forests you control."
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenName$ Treefolk Warrior | TokenTypes$ Creature,Treefolk,Warrior | TokenOwner$ You | TokenColors$ Green | TokenPower$ X | TokenToughness$ X | TokenStaticAbilities$ TokenPT | TokenSVars$ X | References$ X | TokenImage$ g x x treefolk warrior
SVar:TokenPT:Mode$ Continuous | EffectZone$ All | CharacteristicDefining$ True | SetPower$ X | SetToughness$ X | Description$ CARDNAME's power and toughness are each equal to the number of Forests you control.
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ g_x_x_treefolk_warrior | LegacyImage$ g x x treefolk warrior
SVar:BuffedBy:Forest
SVar:NeedsToPlayVar:X GE3
SVar:Picture:http://www.wizards.com/global/images/magic/general/kalonian_twingrove.jpg

View File

@@ -8,6 +8,6 @@ SVar:DBDraw2:DB$ Draw | NumCards$ 1 | ConditionDefined$ Remembered | ConditionPr
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
A:AB$ ChangeZone | Cost$ SubCounter<3/LOYALTY> | Planeswalker$ True | Origin$ Graveyard | Destination$ Battlefield | TargetMin$ 0 | TargetMax$ 2 | TgtPrompt$ Choose target land card in your graveyard | ValidTgts$ Land.YouCtrl | SpellDescription$ Return up to two target land cards from your graveyard to the battlefield.
A:AB$ Destroy | Cost$ SubCounter<11/LOYALTY> | Planeswalker$ True | Ultimate$ True | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | TargetMin$ 0 | TargetMax$ 6 | SubAbility$ DBToken | SpellDescription$ Destroy up to six target nonland permanents, then create six 2/2 green Cat Warrior creature tokens with forestwalk.
SVar:DBToken:DB$ Token | TokenAmount$ 6 | TokenName$ Cat Warrior | TokenTypes$ Creature,Cat,Warrior | TokenOwner$ You | TokenColors$ Green | TokenPower$ 2 | TokenToughness$ 2 | TokenKeywords$ Forestwalk | TokenImage$ g 2 2 cat warrior c18
SVar:DBToken:DB$ Token | TokenAmount$ 6 | TokenOwner$ You | TokenScript$ g_2_2_cat_warrior_forestwalk | LegacyImage$ g 2 2 cat warrior c18
K:CARDNAME can be your commander.
Oracle:[+2]: Discard a card, then draw a card. If a land card is discarded this way, draw an additional card.\n[-3]: Return up to two target land cards from your graveyard to the battlefield.\n[-11]: Destroy up to six target nonland permanents, then create six 2/2 green Cat Warrior creature tokens with forestwalk.\nLord Windgrace can be your commander.

View File

@@ -3,8 +3,6 @@ ManaCost:4 G
Types:Creature Ooze
PT:4/4
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigTokenSenior | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, create two 2/2 green Ooze creature tokens. They have "When this creature dies, create two 1/1 green Ooze creature tokens."
SVar:TrigTokenSenior:DB$Token | TokenImage$ g 2 2 ooze | TokenName$ Ooze | TokenTypes$ Creature,Ooze | TokenColors$ Green | TokenOwner$ You | TokenPower$ 2 | TokenToughness$ 2 | TokenAmount$ 2 | TokenTriggers$ TriggerJunior | TokenSVars$ TrigTokenJunior
SVar:TriggerJunior:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigTokenJunior | TriggerController$ TriggeredCardController | TriggerDescription$ When this creature dies, create two 1/1 green Ooze creature tokens.
SVar:TrigTokenJunior:DB$Token | TokenImage$ g 1 1 ooze | TokenName$ Ooze | TokenTypes$ Creature,Ooze | TokenColors$ Green | TokenOwner$ You | TokenPower$ 1 | TokenToughness$ 1 | TokenAmount$ 2
SVar:TrigTokenSenior:DB$Token | LegacyImage$ g 2 2 ooze | TokenScript$ g_2_2_ooze_mitotic | TokenOwner$ You | TokenAmount$ 2
SVar:Picture:http://www.wizards.com/global/images/magic/general/mitotic_slime.jpg
Oracle:When Mitotic Slime dies, create two 2/2 green Ooze creature tokens. They have "When this creature dies, create two 1/1 green Ooze creature tokens."

View File

@@ -4,8 +4,5 @@ Types:Creature Dragon
PT:5/4
K:Flying
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Land.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Landfall Whenever a land enters the battlefield under your control, create a 0/2 red Dragon creature token with defender and "When this creature dies, create a 2/2 red Dragon creature token with flying and '{R}: This creature gets +1/+0 until end of turn.'"
SVar:TrigToken:DB$ Token | TokenImage$ r 0 2 dragon egg | TokenAmount$ 1 | TokenName$ Dragon Egg | TokenTypes$ Creature,Dragon,Egg | TokenOwner$ You | TokenColors$ Red | TokenPower$ 0 | TokenToughness$ 2 | TokenKeywords$ Defender | TokenTriggers$ TriggerDies | TokenSVars$ TrigToken2,DragonPump
SVar:TriggerDies:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigToken2 | TriggerController$ TriggeredCardController | TriggerDescription$ When this creature dies, create a 2/2 red Dragon creature token with flying and "{R}: This creature gets +1/+0 until end of turn."
SVar:TrigToken2:DB$Token | TokenImage$ r 2 2 dragon c18 | TokenAmount$ 1 | TokenName$ Dragon | TokenTypes$ Creature,Dragon | TokenOwner$ You | TokenColors$ Red | TokenPower$ 2 | TokenToughness$ 2 | TokenKeywords$ Flying | TokenAbilities$ DragonPump
SVar:DragonPump:AB$ Pump | Cost$ R | NumAtt$ +1 | SpellDescription$ CARDNAME gets +1/+0 until end of turn.
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenOwner$ You | LegacyImage$ r 0 2 dragon egg | TokenScript$ r_0_2_dragon_egg_defender_hatches_dragon
Oracle:Flying\nLandfall — Whenever a land enters the battlefield under your control, create a 0/2 red Dragon Egg creature token with defender and "When this creature dies, create a 2/2 red Dragon creature token with flying and '{R}: This creature gets +1/+0 until end of turn.'"

View File

@@ -2,11 +2,7 @@ Name:Reef Worm
ManaCost:3 U
Types:Creature Worm
PT:0/1
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigTokenFish | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, create a 3/3 blue Fish creature token with "When this creature dies, create a 6/6 blue Whale creature token with 'When this creature dies, create a 9/9 blue Kraken creature token.'"
SVar:TrigTokenFish:DB$Token | TokenImage$ u 3 3 fish | TokenName$ Fish | TokenTypes$ Creature,Fish | TokenColors$ Blue | TokenOwner$ You | TokenPower$ 3 | TokenToughness$ 3 | TokenAmount$ 1 | TokenTriggers$ TriggerWhale | TokenSVars$ TrigTokenWhale,TriggerKraken,TrigTokenKraken
SVar:TriggerWhale:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigTokenWhale | TriggerController$ TriggeredCardController | TriggerDescription$ When this creature dies, create a 6/6 blue Whale creature token with "When this creature dies, create a 9/9 blue Kraken creature token."
SVar:TrigTokenWhale:DB$Token | TokenImage$ u 6 6 whale | TokenName$ Whale | TokenTypes$ Creature,Whale | TokenColors$ Blue | TokenOwner$ You | TokenPower$ 6 | TokenToughness$ 6 | TokenAmount$ 1 | TokenTriggers$ TriggerKraken | TokenSVars$ TrigTokenKraken
SVar:TriggerKraken:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigTokenKraken | TriggerController$ TriggeredCardController | TriggerDescription$ When this creature dies, create a 9/9 blue Kraken creature token.
SVar:TrigTokenKraken:DB$Token | TokenImage$ u 9 9 kraken c14 | TokenName$ Kraken | TokenTypes$ Creature,Kraken | TokenColors$ Blue | TokenOwner$ You | TokenPower$ 9 | TokenToughness$ 9 | TokenAmount$ 1
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigToken | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, create a 3/3 blue Fish creature token with "When this creature dies, create a 6/6 blue Whale creature token with 'When this creature dies, create a 9/9 blue Kraken creature token.'"
SVar:TrigToken:DB$Token | LegacyImage$ u 3 3 fish | TokenScript$ u_3_3_fish_hatches_whale | TokenOwner$ You | TokenAmount$ 1
SVar:Picture:http://www.wizards.com/global/images/magic/general/reef_worm.jpg
Oracle:When Reef Worm dies, create a 3/3 blue Fish creature token with "When this creature dies, create a 6/6 blue Whale creature token with 'When this creature dies, create a 9/9 blue Kraken creature token.'"

View File

@@ -6,6 +6,6 @@ K:Flanking
K:Protection from black
K:Suspend:3:1 W W
T:Mode$ CounterRemoved | ValidCard$ Card.Self | TriggerZones$ Exile | CounterType$ TIME | Execute$ TrigToken | IsPresent$ Card.Self+counters_GE1_TIME | PresentZone$ Exile | PresentCompare$ EQ0 | TriggerDescription$ When the last time counter is removed from CARDNAME while it's exiled, create a 2/2 black Knight creature token with flanking, protection from white, and haste.
SVar:TrigToken:DB$Token | TokenAmount$ 1 | TokenName$ Knight | TokenTypes$ Creature,Knight | TokenOwner$ You | TokenColors$ Black | TokenPower$ 2 | TokenToughness$ 2 | TokenKeywords$ Flanking<>Protection from white<>Haste
SVar:TrigToken:DB$Token | TokenAmount$ 1 | TokenOwner$ You | TokenScript$ b_2_2_knight_flanking_pro_white_haste
SVar:Picture:http://www.wizards.com/global/images/magic/general/riftmarked_knight.jpg
Oracle:Protection from black, flanking (Whenever a creature without flanking blocks this creature, the blocking creature gets -1/-1 until end of turn.)\nSuspend 3—{1}{W}{W} (Rather than cast this card from your hand, you may pay {1}{W}{W} and exile it with three time counters on it. At the beginning of your upkeep, remove a time counter. When the last is removed, cast it without paying its mana cost. It has haste.)\nWhen the last time counter is removed from Riftmarked Knight while it's exiled, create a 2/2 black Knight creature token with flanking, protection from white, and haste.

View File

@@ -0,0 +1,9 @@
Name:Knight
ManaCost:no cost
Types:Creature Knight
Colors:black
PT:2/2
K:Flanking
K:Protection from white
K:Haste
Oracle:Flanking\nProtection from white\nHaste

View File

@@ -0,0 +1,6 @@
Name:Ooze
ManaCost:no cost
Types:Creature Ooze
Colors:green
PT:1/1
Oracle:

View File

@@ -0,0 +1,7 @@
Name:Cat Warrior
ManaCost:no cost
Types:Creature Cat Warrior
Colors:green
PT:2/2
K:Forestwalk
Oracle:Forestwalk

View File

@@ -0,0 +1,8 @@
Name:Ooze
ManaCost:no cost
Types:Creature Ooze
Colors:green
PT:2/2
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigTokenJunior | TriggerController$ TriggeredCardController | TriggerDescription$ When this creature dies, create two 1/1 green Ooze creature tokens.
SVar:TrigTokenJunior:DB$Token | LegacyImage$ g 1 1 ooze | TokenScript$ g_1_1_ooze | TokenOwner$ You | TokenAmount$ 2
Oracle:When this creature dies, create two 1/1 green Ooze creature tokens.

View File

@@ -0,0 +1,7 @@
Name:Centaur
ManaCost:no cost
Types:Creature Centaur
Colors:green
PT:3/3
K:Protection from black
Oracle:Protection from black

View File

@@ -0,0 +1,9 @@
Name:Treefolk Warrior
ManaCost:no cost
Types:Creature Treefolk Warrior
Colors:green
PT:*/*
S:Mode$ Continuous | EffectZone$ All | CharacteristicDefining$ True | SetPower$ X | SetToughness$ X | Description$ CARDNAMEs power and toughness are each equal to the number of Forests you control.
SVar:X:Count$Valid Forest.YouCtrl
SVar:BuffedBy:Forest
Oracle:CARDNAMEs power and toughness are each equal to the number of Forests you control.

View File

@@ -0,0 +1,10 @@
Name:Dragon Egg
ManaCost:no cost
Types:Creature Dragon Egg
Colors:red
PT:0/2
K:Defender
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigToken | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, create a 2/2 red Dragon creature token with flying. It has "{R}: This creature gets +1/+0 until end of turn".
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenOwner$ You | LegacyImage$ r 2 2 dragon c18 | TokenScript$ r_2_2_dragon_flying_firebreathing
SVar:SacMe:4
Oracle:Defender\nWhen Dragon Egg dies, create a 2/2 red Dragon creature token with flying. It has "{R}: This creature gets +1/+0 until end of turn."

View File

@@ -0,0 +1,8 @@
Name:Dragon
ManaCost:no cost
Types:Creature Dragon
Colors:red
PT:2/2
K:Flying
A:AB$ Pump | Cost$ R | NumAtt$ +1 | SpellDescription$ CARDNAME gets +1/+0 until end of turn.
Oracle:Flying\n{R}: This creature gets +1/+0 until end of turn.

View File

@@ -0,0 +1,8 @@
Name:Fish
ManaCost:no cost
Types:Creature Fish
Colors:blue
PT:3/3
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigToken | TriggerController$ TriggeredCardController | TriggerDescription$ When this creature dies, create a 6/6 blue Whale creature token with "When this creature dies, create a 9/9 blue Kraken creature token."
SVar:TrigToken:DB$Token | LegacyImage$ u 6 6 whale | TokenScript$ u_6_6_whale_hatches_kraken | TokenOwner$ You | TokenAmount$ 1
Oracle:When this creature dies, create a 6/6 blue Whale creature token with "When this creature dies, create a 9/9 blue Kraken creature token.".

View File

@@ -0,0 +1,8 @@
Name:Whale
ManaCost:no cost
Types:Creature Whale
Colors:blue
PT:6/6
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigToken | TriggerController$ TriggeredCardController | TriggerDescription$ When this creature dies, create a 9/9 blue Kraken creature token.
SVar:TrigToken:DB$Token | LegacyImage$ u 9 9 kraken | TokenScript$ u_9_9_kraken | TokenOwner$ You | TokenAmount$ 1
Oracle:When this creature dies, create a 9/9 blue Kraken creature token.

View File

@@ -0,0 +1,6 @@
Name:Kraken
ManaCost:no cost
Types:Creature Kraken
Colors:blue
PT:9/9
Oracle: