This commit is contained in:
Alessandro Coli
2020-03-12 21:07:17 +01:00
17 changed files with 173 additions and 43 deletions

View File

@@ -113,7 +113,11 @@ public final class ImageKeys {
} }
//try fullborder... //try fullborder...
if (filename.contains(".full")) { if (filename.contains(".full")) {
file = findFile(dir, TextUtil.fastReplace(filename, ".full", ".fullborder")); String fullborderFile = TextUtil.fastReplace(filename, ".full", ".fullborder");
file = findFile(dir, fullborderFile);
if (file != null) { return file; }
// if there's an art variant try without it
file = findFile(dir, TextUtil.fastReplace(fullborderFile, "1.fullborder", ".fullborder"));
if (file != null) { return file; } if (file != null) { return file; }
} }
//if an image, like phenomenon or planes is missing .full in their filenames but you have an existing images that have .full/.fullborder //if an image, like phenomenon or planes is missing .full in their filenames but you have an existing images that have .full/.fullborder

View File

@@ -222,7 +222,12 @@ public final class CardRules implements ICardCharacteristics {
public boolean canBeBrawlCommander() { public boolean canBeBrawlCommander() {
CardType type = mainPart.getType(); CardType type = mainPart.getType();
return (type.isLegendary() && type.isCreature()) || type.isPlaneswalker(); return type.isLegendary() && (type.isCreature() || type.isPlaneswalker());
}
public boolean canBeTinyLeadersCommander() {
CardType type = mainPart.getType();
return type.isLegendary() && (type.isCreature() || type.isPlaneswalker());
} }
public String getMeldWith() { public String getMeldWith() {

View File

@@ -594,8 +594,10 @@ public final class CardRulesPredicates {
public static final Predicate<CardRules> IS_VANGUARD = CardRulesPredicates.coreType(true, CardType.CoreType.Vanguard); public static final Predicate<CardRules> IS_VANGUARD = CardRulesPredicates.coreType(true, CardType.CoreType.Vanguard);
public static final Predicate<CardRules> IS_CONSPIRACY = CardRulesPredicates.coreType(true, CardType.CoreType.Conspiracy); public static final Predicate<CardRules> IS_CONSPIRACY = CardRulesPredicates.coreType(true, CardType.CoreType.Conspiracy);
public static final Predicate<CardRules> IS_NON_LAND = CardRulesPredicates.coreType(false, CardType.CoreType.Land); public static final Predicate<CardRules> IS_NON_LAND = CardRulesPredicates.coreType(false, CardType.CoreType.Land);
public static final Predicate<CardRules> CAN_BE_BRAWL_COMMANDER = Predicates.or(Presets.IS_PLANESWALKER, public static final Predicate<CardRules> CAN_BE_BRAWL_COMMANDER = Predicates.and(Presets.IS_LEGENDARY,
Predicates.and(Presets.IS_CREATURE, Presets.IS_LEGENDARY)); Predicates.or(Presets.IS_CREATURE, Presets.IS_PLANESWALKER));
public static final Predicate<CardRules> CAN_BE_TINY_LEADERS_COMMANDER = Predicates.and(Presets.IS_LEGENDARY,
Predicates.or(Presets.IS_CREATURE, Presets.IS_PLANESWALKER));
/** The Constant IS_NON_CREATURE_SPELL. **/ /** The Constant IS_NON_CREATURE_SPELL. **/
public static final Predicate<CardRules> IS_NON_CREATURE_SPELL = com.google.common.base.Predicates public static final Predicate<CardRules> IS_NON_CREATURE_SPELL = com.google.common.base.Predicates

View File

@@ -463,6 +463,9 @@ public enum DeckFormat {
if (this.equals(DeckFormat.Brawl)) { if (this.equals(DeckFormat.Brawl)) {
return rules.canBeBrawlCommander(); return rules.canBeBrawlCommander();
} }
if (this.equals(DeckFormat.TinyLeaders)) {
return rules.canBeTinyLeadersCommander();
}
return rules.canBeCommander(); return rules.canBeCommander();
} }

View File

@@ -22,8 +22,10 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import forge.card.MagicColor;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostParser; import forge.card.mana.ManaCostParser;
import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.*; import forge.game.card.*;
@@ -32,9 +34,15 @@ import forge.game.cost.Cost;
import forge.game.keyword.KeywordInterface; import forge.game.keyword.KeywordInterface;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.player.PlayerController; import forge.game.player.PlayerController;
import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementHandler;
import forge.game.replacement.ReplacementLayer;
import forge.game.spellability.*; import forge.game.spellability.*;
import forge.game.trigger.Trigger; import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerHandler;
import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.Lang;
import forge.util.TextUtil; import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -363,10 +371,11 @@ public final class GameActionUtil {
} }
SpellAbility result = null; SpellAbility result = null;
final Card host = sa.getHostCard(); final Card host = sa.getHostCard();
final Game game = host.getGame();
final Player activator = sa.getActivatingPlayer(); final Player activator = sa.getActivatingPlayer();
final PlayerController pc = activator.getController(); final PlayerController pc = activator.getController();
host.getGame().getAction().checkStaticAbilities(false); game.getAction().checkStaticAbilities(false);
boolean reset = false; boolean reset = false;
@@ -429,7 +438,60 @@ public final class GameActionUtil {
int v = pc.chooseNumberForKeywordCost(sa, cost, ki, str, Integer.MAX_VALUE); int v = pc.chooseNumberForKeywordCost(sa, cost, ki, str, Integer.MAX_VALUE);
if (v > 0) { if (v > 0) {
host.addReplacementEffect(CardFactoryUtil.makeEtbCounter("etbCounter:P1P1:" + v, host, false));
final Card eff = new Card(game.nextCardId(), game);
eff.setTimestamp(game.getNextTimestamp());
eff.setName(c.getName() + "'s Effect");
eff.addType("Effect");
eff.setToken(true); // Set token to true, so when leaving play it gets nuked
eff.setOwner(activator);
eff.setImageKey(c.getImageKey());
eff.setColor(MagicColor.COLORLESS);
eff.setImmutable(true);
// try to get the SpellAbility from the mana ability
//eff.setEffectSource((SpellAbility)null);
eff.addRemembered(host);
String abStr = "DB$ PutCounter | Defined$ ReplacedCard | CounterType$ P1P1 | ETB$ True | CounterNum$ " + v;
SpellAbility saAb = AbilityFactory.getAbility(abStr, c);
CardFactoryUtil.setupETBReplacementAbility(saAb);
String desc = "It enters the battlefield with ";
desc += Lang.nounWithNumeral(v, CounterType.P1P1.getName() + " counter");
desc += " on it.";
String repeffstr = "Event$ Moved | ValidCard$ Card.IsRemembered | Destination$ Battlefield | Description$ " + desc;
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, eff, true);
re.setLayer(ReplacementLayer.Other);
re.setOverridingAbility(saAb);
eff.addReplacementEffect(re);
// Forgot Trigger
String trig = "Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Stack | Destination$ Any | TriggerZones$ Command | Static$ True";
String forgetEffect = "DB$ Pump | ForgetObjects$ TriggeredCard";
String exileEffect = "DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile"
+ " | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0";
SpellAbility saForget = AbilityFactory.getAbility(forgetEffect, eff);
AbilitySub saExile = (AbilitySub) AbilityFactory.getAbility(exileEffect, eff);
saForget.setSubAbility(saExile);
final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, eff, true);
parsedTrigger.setOverridingAbility(saForget);
eff.addTrigger(parsedTrigger);
eff.updateStateForView();
// TODO: Add targeting to the effect so it knows who it's dealing with
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
game.getAction().moveTo(ZoneType.Command, eff, null);
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
if (result == null) { if (result == null) {
result = sa.copy(); result = sa.copy();
} }

View File

@@ -254,7 +254,7 @@ public class ManaPool extends ManaConversionMatrix implements Iterable<Mana> {
} }
} }
if (mana.addsCounters(sa)) { if (mana.addsCounters(sa)) {
mana.getManaAbility().createETBCounters(host); mana.getManaAbility().createETBCounters(host, this.owner);
} }
if (mana.triggersWhenSpent()) { if (mana.triggersWhenSpent()) {
mana.getManaAbility().addTriggersWhenSpent(sa, host); mana.getManaAbility().addTriggersWhenSpent(sa, host);

View File

@@ -6,23 +6,24 @@
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package forge.game.spellability; package forge.game.spellability;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.card.mana.ManaAtom; import forge.card.mana.ManaAtom;
import forge.game.Game;
import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.card.Card; import forge.game.card.Card;
@@ -35,6 +36,8 @@ import forge.game.replacement.*;
import forge.game.trigger.Trigger; import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerHandler; import forge.game.trigger.TriggerHandler;
import forge.game.trigger.TriggerType; import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType;
import forge.util.Lang;
import forge.util.TextUtil; import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -47,7 +50,7 @@ import java.util.regex.Pattern;
* <p> * <p>
* Abstract AbilityMana class. * Abstract AbilityMana class.
* </p> * </p>
* *
* @author Forge * @author Forge
* @version $Id$ * @version $Id$
*/ */
@@ -79,7 +82,7 @@ public class AbilityManaPart implements java.io.Serializable {
* <p> * <p>
* Constructor for AbilityMana. * Constructor for AbilityMana.
* </p> * </p>
* *
* @param sourceCard * @param sourceCard
* a {@link forge.game.card.Card} object. * a {@link forge.game.card.Card} object.
*/ */
@@ -112,7 +115,7 @@ public class AbilityManaPart implements java.io.Serializable {
* <p> * <p>
* produceMana. * produceMana.
* </p> * </p>
* *
* @param produced * @param produced
* a {@link java.lang.String} object. * a {@link java.lang.String} object.
* @param player * @param player
@@ -170,7 +173,7 @@ public class AbilityManaPart implements java.io.Serializable {
* cannotCounterPaidWith. * cannotCounterPaidWith.
* </p> * </p>
* @param saBeingPaid * @param saBeingPaid
* *
* @return a {@link java.lang.String} object. * @return a {@link java.lang.String} object.
*/ */
public boolean cannotCounterPaidWith(SpellAbility saBeingPaid) { public boolean cannotCounterPaidWith(SpellAbility saBeingPaid) {
@@ -187,7 +190,7 @@ public class AbilityManaPart implements java.io.Serializable {
* addKeywords. * addKeywords.
* </p> * </p>
* @param saBeingPaid * @param saBeingPaid
* *
* @return a {@link java.lang.String} object. * @return a {@link java.lang.String} object.
*/ */
public boolean addKeywords(SpellAbility saBeingPaid) { public boolean addKeywords(SpellAbility saBeingPaid) {
@@ -206,7 +209,7 @@ public class AbilityManaPart implements java.io.Serializable {
* <p> * <p>
* getKeywords. * getKeywords.
* </p> * </p>
* *
* @return a {@link java.lang.String} object. * @return a {@link java.lang.String} object.
*/ */
public String getKeywords() { public String getKeywords() {
@@ -218,7 +221,7 @@ public class AbilityManaPart implements java.io.Serializable {
* addsCounters. * addsCounters.
* </p> * </p>
* @param saBeingPaid * @param saBeingPaid
* *
* @return a {@link java.lang.String} object. * @return a {@link java.lang.String} object.
*/ */
public boolean addsCounters(SpellAbility saBeingPaid) { public boolean addsCounters(SpellAbility saBeingPaid) {
@@ -228,10 +231,26 @@ public class AbilityManaPart implements java.io.Serializable {
/** /**
* createETBCounters * createETBCounters
*/ */
public void createETBCounters(Card c) { public void createETBCounters(Card c, Player controller) {
String[] parse = this.addsCounters.split("_"); String[] parse = this.addsCounters.split("_");
// Convert random SVars if there are other cards with this effect // Convert random SVars if there are other cards with this effect
if (c.isValid(parse[0], c.getController(), c, null)) { if (c.isValid(parse[0], c.getController(), c, null)) {
final Game game = this.sourceCard.getGame();
final Card eff = new Card(game.nextCardId(), game);
eff.setTimestamp(game.getNextTimestamp());
eff.setName(sourceCard.getName() + "'s Effect");
eff.addType("Effect");
eff.setToken(true); // Set token to true, so when leaving play it gets nuked
eff.setOwner(controller);
eff.setImageKey(sourceCard.getImageKey());
eff.setColor(MagicColor.COLORLESS);
eff.setImmutable(true);
// try to get the SpellAbility from the mana ability
//eff.setEffectSource((SpellAbility)null);
eff.addRemembered(c);
String abStr = "DB$ PutCounter | Defined$ ReplacedCard | CounterType$ " + parse[1] String abStr = "DB$ PutCounter | Defined$ ReplacedCard | CounterType$ " + parse[1]
+ " | ETB$ True | CounterNum$ " + parse[2]; + " | ETB$ True | CounterNum$ " + parse[2];
@@ -241,15 +260,37 @@ public class AbilityManaPart implements java.io.Serializable {
} }
CardFactoryUtil.setupETBReplacementAbility(sa); CardFactoryUtil.setupETBReplacementAbility(sa);
String repeffstr = "Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield " String desc = "It enters the battlefield with ";
+ " | Secondary$ True | Description$ CARDNAME" desc += Lang.nounWithNumeral(parse[2], CounterType.valueOf(parse[1]).getName() + " counter");
+ " enters the battlefield with " + CounterType.valueOf(parse[1]).getName() + " counters."; desc += " on it.";
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, c, false); String repeffstr = "Event$ Moved | ValidCard$ Card.IsRemembered | Destination$ Battlefield | Description$ " + desc;
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, eff, true);
re.setLayer(ReplacementLayer.Other); re.setLayer(ReplacementLayer.Other);
re.setOverridingAbility(sa); re.setOverridingAbility(sa);
c.addChangedCardTraits(null, null, null, ImmutableList.of(re), null, false, false, false, sa.getHostCard().getGame().getNextTimestamp()); eff.addReplacementEffect(re);
// Forgot Trigger
String trig = "Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Stack | Destination$ Any | TriggerZones$ Command | Static$ True";
String forgetEffect = "DB$ Pump | ForgetObjects$ TriggeredCard";
String exileEffect = "DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile"
+ " | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0";
SpellAbility saForget = AbilityFactory.getAbility(forgetEffect, eff);
AbilitySub saExile = (AbilitySub) AbilityFactory.getAbility(exileEffect, eff);
saForget.setSubAbility(saExile);
final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, eff, true);
parsedTrigger.setOverridingAbility(saForget);
eff.addTrigger(parsedTrigger);
eff.updateStateForView();
// TODO: Add targeting to the effect so it knows who it's dealing with
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
game.getAction().moveTo(ZoneType.Command, eff, null);
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
} }
} }
@@ -270,7 +311,7 @@ public class AbilityManaPart implements java.io.Serializable {
* <p> * <p>
* getManaRestrictions. * getManaRestrictions.
* </p> * </p>
* *
* @return a {@link java.lang.String} object. * @return a {@link java.lang.String} object.
*/ */
public String getManaRestrictions() { public String getManaRestrictions() {
@@ -281,7 +322,7 @@ public class AbilityManaPart implements java.io.Serializable {
* <p> * <p>
* meetsManaRestrictions. * meetsManaRestrictions.
* </p> * </p>
* *
* @param sa * @param sa
* a {@link forge.game.spellability.SpellAbility} object. * a {@link forge.game.spellability.SpellAbility} object.
* @return a boolean. * @return a boolean.
@@ -297,7 +338,7 @@ public class AbilityManaPart implements java.io.Serializable {
if (restriction.equals("nonSpell")) { if (restriction.equals("nonSpell")) {
return !sa.isSpell(); return !sa.isSpell();
} }
if (restriction.equals("CumulativeUpkeep")) { if (restriction.equals("CumulativeUpkeep")) {
if (sa.isCumulativeupkeep()) { if (sa.isCumulativeupkeep()) {
return true; return true;
@@ -350,7 +391,7 @@ public class AbilityManaPart implements java.io.Serializable {
* <p> * <p>
* mana. * mana.
* </p> * </p>
* *
* @return a {@link java.lang.String} object. * @return a {@link java.lang.String} object.
*/ */
public final String mana() { public final String mana() {
@@ -439,7 +480,7 @@ public class AbilityManaPart implements java.io.Serializable {
* <p> * <p>
* canProduce. * canProduce.
* </p> * </p>
* *
* @param s * @param s
* a {@link java.lang.String} object. * a {@link java.lang.String} object.
* @return a boolean. * @return a boolean.
@@ -469,7 +510,7 @@ public class AbilityManaPart implements java.io.Serializable {
* <p> * <p>
* isBasic. * isBasic.
* </p> * </p>
* *
* @return a boolean. * @return a boolean.
*/ */
public final boolean isBasic() { public final boolean isBasic() {
@@ -542,7 +583,7 @@ public class AbilityManaPart implements java.io.Serializable {
public Card getSourceCard() { public Card getSourceCard() {
return sourceCard; return sourceCard;
} }
public void setSourceCard(final Card host) { public void setSourceCard(final Card host) {
sourceCard = host; sourceCard = host;
} }

View File

@@ -103,7 +103,7 @@ public final class CEditorConstructed extends CDeckEditor<Deck> {
case TinyLeaders: case TinyLeaders:
allSections.add(DeckSection.Commander); allSections.add(DeckSection.Commander);
commanderFilter = CardRulesPredicates.Presets.CAN_BE_COMMANDER; commanderFilter = CardRulesPredicates.Presets.CAN_BE_TINY_LEADERS_COMMANDER;
commanderPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(Predicates.compose(commanderFilter, PaperCard.FN_GET_RULES)), PaperCard.class); commanderPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(Predicates.compose(commanderFilter, PaperCard.FN_GET_RULES)), PaperCard.class);
normalPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(), PaperCard.class); normalPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(), PaperCard.class);

View File

@@ -856,6 +856,9 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
case Brawl: case Brawl:
isLegalCommander = card.getRules().canBeBrawlCommander(); isLegalCommander = card.getRules().canBeBrawlCommander();
break; break;
case TinyLeaders:
isLegalCommander = card.getRules().canBeTinyLeadersCommander();
break;
case Oathbreaker: case Oathbreaker:
isLegalCommander = card.getRules().canBeOathbreaker(); isLegalCommander = card.getRules().canBeOathbreaker();
captionSuffix = localizer.getMessage("lblOathbreaker"); captionSuffix = localizer.getMessage("lblOathbreaker");

View File

@@ -84,4 +84,4 @@ Modern Horizons, 3/6/WAR, MH1
Core Set 2020, 3/6/M20, M20 Core Set 2020, 3/6/M20, M20
Throne of Eldraine, 3/6/ELD, ELD Throne of Eldraine, 3/6/ELD, ELD
Theros Beyond Death, 3/6/THB, THB Theros Beyond Death, 3/6/THB, THB
Mystery Booster, 3/6/MB1, MB1 Mystery Booster, 3/6/THB, MB1

View File

@@ -1,7 +1,7 @@
Name:Ghastly Demise Name:Ghastly Demise
ManaCost:B ManaCost:B
Types:Instant Types:Instant
A:SP$ Destroy | Cost$ B | ValidTgts$ Creature.nonBlack+toughnessLEX | TgtPrompt$ Select target nonblack creature with toughness less than or equal to the number of cards in your graveyard. | References$ X | SpellDescription$ Destroy target nonblack creature if its toughness is less than or equal to the number of cards in your graveyard. A:SP$ Destroy | Cost$ B | ValidTgts$ Creature.nonBlack | TgtPrompt$ Select target nonblack creature | ConditionCheckSVar$ Y | ConditionSVarCompare$ LEX | References$ X,Y | StackDescription$ SpellDescription | SpellDescription$ Destroy target nonblack creature if its toughness is less than or equal to the number of cards in your graveyard.
SVar:Y:Targeted$CardToughness
SVar:X:Count$InYourYard SVar:X:Count$InYourYard
SVar:Picture:http://www.wizards.com/global/images/magic/general/ghastly_demise.jpg
Oracle:Destroy target nonblack creature if its toughness is less than or equal to the number of cards in your graveyard. Oracle:Destroy target nonblack creature if its toughness is less than or equal to the number of cards in your graveyard.

View File

@@ -1,9 +1,10 @@
Name:Nissa's Pilgrimage Name:Nissa's Pilgrimage
ManaCost:2 G ManaCost:2 G
Types:Sorcery Types:Sorcery
A:SP$ ChangeZone | Cost$ 2 G | Origin$ Library | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.Basic+Forest | ChangeNum$ 1 | SubAbility$ DBChangeZone1 | NoShuffle$ True | SpellDescription$ Search your library for up to two basic Forest cards, reveal those cards, and put one onto the battlefield tapped and the rest into your hand. Then shuffle your library. Spell mastery — If there are two or more instant or sorcery cards in your graveyard, search your library for up to three basic Forest cards instead of two. A:SP$ ChangeZone | Cost$ 2 G | Origin$ Library | Destination$ Library | ChangeType$ Land.Basic+Forest | ChangeNum$ X | References$ X,Y | RememberChanged$ True | SubAbility$ DBBattlefield | Shuffle$ False | StackDescription$ SpellDescription | SpellDescription$ Search your library for up to two basic Forest cards, reveal those cards, and put one onto the battlefield tapped and the rest into your hand. Then shuffle your library. Spell mastery — If there are two or more instant or sorcery cards in your graveyard, search your library for up to three basic Forest cards instead of two.
SVar:DBChangeZone1:DB$ChangeZone | Origin$ Library | Destination$ Hand | SubAbility$ DBChangeZone2 | ChangeType$ Land.Basic+Forest | ChangeNum$ 1 | ConditionCheckSVar$ X | ConditionSVarCompare$ LT2 | References$ X SVar:DBBattlefield:DB$ ChangeZone | Origin$ Library | Destination$ Battlefield | Tapped$ True | SubAbility$ DBHand | ChangeType$ Card.IsRemembered | ChangeNum$ 1 | Mandatory$ True | NoLooking$ True | SelectPrompt$ Select a card to go to the battlefield | Shuffle$ False | StackDescription$ None
SVar:DBChangeZone2:DB$ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Land.Basic+Forest | ChangeNum$ 2 | ConditionCheckSVar$ X | ConditionSVarCompare$ GE2 | References$ X SVar:DBHand:DB$ ChangeZone | Origin$ Library | Destination$ Hand | Defined$ Remembered | NoLooking$ True | StackDescription$ None | SubAbility$ DBCleanup
SVar:X:Count$ValidGraveyard Instant.YouOwn,Sorcery.YouOwn SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:Picture:http://www.wizards.com/global/images/magic/general/nissas_pilgrimage.jpg SVar:X:Count$Compare Y GE2.3.2
SVar:Y:Count$ValidGraveyard Instant.YouOwn,Sorcery.YouOwn
Oracle:Search your library for up to two basic Forest cards, reveal those cards, and put one onto the battlefield tapped and the rest into your hand. Then shuffle your library.\nSpell mastery — If there are two or more instant or sorcery cards in your graveyard, search your library for up to three basic Forest cards instead of two. Oracle:Search your library for up to two basic Forest cards, reveal those cards, and put one onto the battlefield tapped and the rest into your hand. Then shuffle your library.\nSpell mastery — If there are two or more instant or sorcery cards in your graveyard, search your library for up to three basic Forest cards instead of two.

View File

@@ -3,7 +3,7 @@ ManaCost:1 W
Types:Enchantment Saga Types:Enchantment Saga
K:Saga:3:TrigChange,TrigToken,TrigGainLife K:Saga:3:TrigChange,TrigToken,TrigGainLife
SVar:TrigChange:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Land.Plains+Basic | ChangeNum$ 1 | SpellDescription$ Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle your library. SVar:TrigChange:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Land.Plains+Basic | ChangeNum$ 1 | SpellDescription$ Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle your library.
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_0_4_wall_defender | TokenOwner$ You | LegacyImage$ c 0 4 wall defender thb | SpellDescription$ Create a 0/4 colorless Wall artifact creature token with defender. SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_0_4_a_wall_defender | TokenOwner$ You | LegacyImage$ c 0 4 wall defender thb | SpellDescription$ Create a 0/4 colorless Wall artifact creature token with defender.
SVar:TrigGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 2 | SpellDescription$ You gain 2 life. SVar:TrigGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 2 | SpellDescription$ You gain 2 life.
DeckHas:Ability$LifeGain & Ability$Token DeckHas:Ability$LifeGain & Ability$Token
Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)\nI - Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle your library.\nII - Create a 0/4 colorless Wall artifact creature token with defender.\nIII - You gain 2 life. Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)\nI - Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle your library.\nII - Create a 0/4 colorless Wall artifact creature token with defender.\nIII - You gain 2 life.

View File

@@ -377,7 +377,7 @@ Prerelease=6 Boosters, 1 RareMythic+
[tokens] [tokens]
b_2_2_zombie b_2_2_zombie
c_0_4_wall_defender c_0_4_a_wall_defender
g_1_2_spider_reach g_1_2_spider_reach
g_2_2_wolf g_2_2_wolf
r_x_1_elemental_trample_haste r_x_1_elemental_trample_haste

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -1,6 +1,6 @@
Name:Wall Name:Wall
ManaCost:no cost ManaCost:no cost
Types:Creature Wall Types:Artifact Creature Wall
PT:0/4 PT:0/4
K:Defender K:Defender
Oracle:Defender Oracle:Defender

View File

@@ -6,6 +6,8 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import forge.FThreads; import forge.FThreads;
import forge.ImageKeys; import forge.ImageKeys;
@@ -50,7 +52,14 @@ public abstract class ImageFetcher {
setDownload.append(ImageUtil.getDownloadUrl(paperCard, backFace)); setDownload.append(ImageUtil.getDownloadUrl(paperCard, backFace));
downloadUrls.add(setDownload.toString()); downloadUrls.add(setDownload.toString());
int artIndex = Integer.parseInt(imageKey.split("\\|")[2]); int artIndex = 1;
final Pattern pattern = Pattern.compile(
"^.:([^|]*\\|){2}(\\d+).*$"
);
Matcher matcher = pattern.matcher(imageKey);
if (matcher.matches()) {
artIndex = Integer.parseInt(matcher.group(2));
}
final StaticData data = StaticData.instance(); final StaticData data = StaticData.instance();
final String cardNum = data.getCommonCards().getCardCollectorNumber(paperCard.getName(), paperCard.getEdition(), artIndex); final String cardNum = data.getCommonCards().getCardCollectorNumber(paperCard.getName(), paperCard.getEdition(), artIndex);
if (cardNum != null) { if (cardNum != null) {