mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 03:08:02 +00:00
Merge remote-tracking branch 'upstream/master' into collector-number-in-card-list-and-card-db-refactoring
This commit is contained in:
@@ -389,7 +389,7 @@ public class AiController {
|
||||
final List<SpellAbility> spellAbility = Lists.newArrayList();
|
||||
for (final Card c : l) {
|
||||
for (final SpellAbility sa : c.getNonManaAbilities()) {
|
||||
// Check if this AF is a Counterpsell
|
||||
// Check if this AF is a Counterspell
|
||||
if (sa.getApi() == ApiType.Counter) {
|
||||
spellAbility.add(sa);
|
||||
}
|
||||
|
||||
@@ -1307,7 +1307,7 @@ public class ComputerUtil {
|
||||
}
|
||||
if (abCost.hasTapCost() && source.hasSVar("AITapDown")) {
|
||||
return true;
|
||||
} else if (sa.hasParam("Planeswalker") && ai.getGame().getPhaseHandler().is(PhaseType.MAIN2)) {
|
||||
} else if (sa.isPwAbility() && ai.getGame().getPhaseHandler().is(PhaseType.MAIN2)) {
|
||||
for (final CostPart part : abCost.getCostParts()) {
|
||||
if (part instanceof CostPutCounter) {
|
||||
return true;
|
||||
@@ -2859,7 +2859,6 @@ public class ComputerUtil {
|
||||
public static boolean lifegainNegative(final Player player, final Card source) {
|
||||
return lifegainNegative(player, source, 1);
|
||||
}
|
||||
|
||||
public static boolean lifegainNegative(final Player player, final Card source, final int n) {
|
||||
if (!player.canGainLife()) {
|
||||
return false;
|
||||
|
||||
@@ -1236,7 +1236,7 @@ public abstract class GameState {
|
||||
// (will be overridden later, so the actual value shouldn't matter)
|
||||
|
||||
//FIXME it shouldn't be able to attach itself
|
||||
c.setEntityAttachedTo(c);
|
||||
c.setEntityAttachedTo(CardFactory.copyCard(c, true));
|
||||
}
|
||||
|
||||
if (cardsWithoutETBTrigs.contains(c)) {
|
||||
|
||||
@@ -98,4 +98,3 @@ public class AmassAi extends SpellAbilityAi {
|
||||
return ComputerUtilCard.getBestAI(better);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@ public class AnimateAi extends SpellAbilityAi {
|
||||
private boolean animateTgtAI(final SpellAbility sa) {
|
||||
final Player ai = sa.getActivatingPlayer();
|
||||
final PhaseHandler ph = ai.getGame().getPhaseHandler();
|
||||
final boolean alwaysActivatePWAbility = sa.hasParam("Planeswalker")
|
||||
final boolean alwaysActivatePWAbility = sa.isPwAbility()
|
||||
&& sa.getPayCosts().hasSpecificCostType(CostPutCounter.class)
|
||||
&& sa.getTargetRestrictions() != null
|
||||
&& sa.getTargetRestrictions().getMinTargets(sa.getHostCard(), sa) == 0;
|
||||
|
||||
@@ -50,7 +50,6 @@ public final class BondAi extends SpellAbilityAi {
|
||||
return true;
|
||||
} // end bondCanPlayAI()
|
||||
|
||||
|
||||
@Override
|
||||
protected Card chooseSingleCard(Player ai, SpellAbility sa, Iterable<Card> options, boolean isOptional, Player targetedPlayer, Map<String, Object> params) {
|
||||
return ComputerUtilCard.getBestCreatureAI(options);
|
||||
|
||||
@@ -36,7 +36,6 @@ public class CanPlayAsDrawbackAi extends SpellAbilityAi {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SpellAbility chooseSingleSpellAbility(Player player, SpellAbility sa, List<SpellAbility> spells,
|
||||
Map<String, Object> params) {
|
||||
|
||||
@@ -1130,7 +1130,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
|
||||
boolean doWithoutTarget = sa.hasParam("Planeswalker") && sa.usesTargeting()
|
||||
boolean doWithoutTarget = sa.isPwAbility() && sa.usesTargeting()
|
||||
&& sa.getMinTargets() == 0
|
||||
&& sa.getPayCosts().hasSpecificCostType(CostPutCounter.class);
|
||||
|
||||
|
||||
@@ -30,8 +30,7 @@ public class CharmAi extends SpellAbilityAi {
|
||||
final int min;
|
||||
if (sa.isEntwine()) {
|
||||
num = min = choices.size();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
num = AbilityUtils.calculateAmount(source, sa.getParamOrDefault("CharmNum", "1"), sa);
|
||||
min = sa.hasParam("MinCharmNum") ? AbilityUtils.calculateAmount(source, sa.getParamOrDefault("MinCharmNum", "1"), sa) : num;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ public class ClashAi extends SpellAbilityAi {
|
||||
return legalAction;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
|
||||
@@ -64,7 +64,6 @@ public class CounterAi extends SpellAbilityAi {
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
if (tgt != null) {
|
||||
|
||||
final SpellAbility topSA = ComputerUtilAbility.getTopSpellAbilityOnStack(game, sa);
|
||||
if (!CardFactoryUtil.isCounterableBy(topSA.getHostCard(), sa) || topSA.getActivatingPlayer() == ai
|
||||
|| ai.getAllies().contains(topSA.getActivatingPlayer())) {
|
||||
@@ -317,7 +316,7 @@ public class CounterAi extends SpellAbilityAi {
|
||||
|
||||
Iterator<SpellAbilityStackInstance> it = game.getStack().iterator();
|
||||
SpellAbilityStackInstance si = null;
|
||||
while(it.hasNext()) {
|
||||
while (it.hasNext()) {
|
||||
si = it.next();
|
||||
tgtSA = si.getSpellAbility(true);
|
||||
if (!sa.canTargetSpellAbility(tgtSA)) {
|
||||
|
||||
@@ -501,7 +501,7 @@ public class CountersPutAi extends SpellAbilityAi {
|
||||
// Activate +Loyalty planeswalker abilities even if they have no target (e.g. Vivien of the Arkbow),
|
||||
// but try to do it in Main 2 then so that the AI has a chance to play creatures first.
|
||||
if (list.isEmpty()
|
||||
&& sa.hasParam("Planeswalker")
|
||||
&& sa.isPwAbility()
|
||||
&& sa.getPayCosts().hasOnlySpecificCostType(CostPutCounter.class)
|
||||
&& sa.isTargetNumberValid()
|
||||
&& sa.getTargets().size() == 0
|
||||
|
||||
@@ -57,7 +57,6 @@ public final class EncodeAi extends SpellAbilityAi {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean chkAIDrawback(SpellAbility sa, Player ai) {
|
||||
return true;
|
||||
|
||||
@@ -69,4 +69,3 @@ public class ExploreAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ public class FlipACoinAi extends SpellAbilityAi {
|
||||
*/
|
||||
@Override
|
||||
protected boolean canPlayAI(Player ai, SpellAbility sa) {
|
||||
|
||||
if (sa.hasParam("AILogic")) {
|
||||
String ailogic = sa.getParam("AILogic");
|
||||
if (ailogic.equals("Never")) {
|
||||
|
||||
@@ -24,4 +24,3 @@ public class InvestigateAi extends SpellAbilityAi {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,6 @@ public class LifeExchangeAi extends SpellAbilityAi {
|
||||
@Override
|
||||
protected boolean doTriggerAINoCost(final Player ai, final SpellAbility sa,
|
||||
final boolean mandatory) {
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
Player opp = AiAttackController.choosePreferredDefenderPlayer(ai);
|
||||
if (tgt != null) {
|
||||
|
||||
@@ -53,7 +53,7 @@ public class MillAi extends SpellAbilityAi {
|
||||
} else if ("ExileAndPlayOrDealDamage".equals(sa.getParam("AILogic"))) {
|
||||
return (ph.is(PhaseType.MAIN1) || ph.is(PhaseType.MAIN2)) && ph.isPlayerTurn(ai); // Chandra, Torch of Defiance and similar
|
||||
}
|
||||
if (!sa.hasParam("Planeswalker")) { // Planeswalker abilities are only activated at sorcery speed
|
||||
if (!sa.isPwAbility()) { // Planeswalker abilities are only activated at sorcery speed
|
||||
if ("You".equals(sa.getParam("Defined")) && !(!SpellAbilityAi.isSorcerySpeed(sa) && ph.is(PhaseType.END_OF_TURN)
|
||||
&& ph.getNextTurn().equals(ai))) {
|
||||
return false; // only self-mill at opponent EOT
|
||||
|
||||
@@ -24,7 +24,6 @@ public class ScryAi extends SpellAbilityAi {
|
||||
*/
|
||||
@Override
|
||||
protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) {
|
||||
|
||||
if (sa.usesTargeting()) { // It doesn't appear that Scry ever targets
|
||||
// ability is targeted
|
||||
sa.resetTargets();
|
||||
@@ -69,7 +68,7 @@ public class ScryAi extends SpellAbilityAi {
|
||||
// in the playerturn Scry should only be done in Main1 or in upkeep if able
|
||||
if (ph.isPlayerTurn(ai)) {
|
||||
if (SpellAbilityAi.isSorcerySpeed(sa)) {
|
||||
return ph.is(PhaseType.MAIN1) || sa.hasParam("Planeswalker");
|
||||
return ph.is(PhaseType.MAIN1) || sa.isPwAbility();
|
||||
} else {
|
||||
return ph.is(PhaseType.UPKEEP);
|
||||
}
|
||||
|
||||
@@ -199,7 +199,6 @@ public class SetStateAi extends SpellAbilityAi {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// check which state would be better for attacking
|
||||
if (ph.isPlayerTurn(ai) && ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
|
||||
boolean transformAttack = false;
|
||||
|
||||
@@ -66,7 +66,6 @@ public class StoreSVarAi extends SpellAbilityAi {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ public class SurveilAi extends SpellAbilityAi {
|
||||
*/
|
||||
@Override
|
||||
protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) {
|
||||
|
||||
if (sa.usesTargeting()) { // TODO: It doesn't appear that Surveil ever targets, is this necessary?
|
||||
sa.resetTargets();
|
||||
sa.getTargets().add(ai);
|
||||
@@ -60,7 +59,7 @@ public class SurveilAi extends SpellAbilityAi {
|
||||
// in the player's turn Surveil should only be done in Main1 or in Upkeep if able
|
||||
if (ph.isPlayerTurn(ai)) {
|
||||
if (SpellAbilityAi.isSorcerySpeed(sa)) {
|
||||
return ph.is(PhaseType.MAIN1) || sa.hasParam("Planeswalker");
|
||||
return ph.is(PhaseType.MAIN1) || sa.isPwAbility();
|
||||
} else {
|
||||
return ph.is(PhaseType.UPKEEP);
|
||||
}
|
||||
|
||||
@@ -47,8 +47,7 @@ public class TwoPilesAi extends SpellAbilityAi {
|
||||
CardCollectionView pool;
|
||||
if (sa.hasParam("DefinedCards")) {
|
||||
pool = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("DefinedCards"), sa);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
pool = p.getCardsIn(zone);
|
||||
}
|
||||
pool = CardLists.getValidCards(pool, valid, card.getController(), card, sa);
|
||||
|
||||
@@ -224,7 +224,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
}
|
||||
|
||||
artIds.put(key, artIdx);
|
||||
addCard(new PaperCard(cr, e.getCode(), cis.rarity, artIdx, cis.collectorNumber));
|
||||
addCard(new PaperCard(cr, e.getCode(), cis.rarity, artIdx, false, cis.collectorNumber, cis.artistName));
|
||||
}
|
||||
|
||||
public void loadCard(String cardName, CardRules cr) {
|
||||
@@ -236,6 +236,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
for (CardInSet cis : cardsInSet)
|
||||
addSetCard(e, cis, cr);
|
||||
}
|
||||
|
||||
reIndex();
|
||||
}
|
||||
|
||||
@@ -289,10 +290,10 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
for (CardRules cr : rulesByName.values()) {
|
||||
if (!contains(cr.getName())) {
|
||||
if (upcomingSet != null) {
|
||||
addCard(new PaperCard(cr, upcomingSet.getCode(), CardRarity.Unknown));
|
||||
addCard(new PaperCard(cr, upcomingSet.getCode(), CardRarity.Unknown, IPaperCard.DEFAULT_ART_INDEX));
|
||||
} else if (enableUnknownCards && !this.filtered.contains(cr.getName())) {
|
||||
System.err.println("The card " + cr.getName() + " was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. ");
|
||||
addCard(new PaperCard(cr, CardEdition.UNKNOWN.getCode(), CardRarity.Special));
|
||||
addCard(new PaperCard(cr, CardEdition.UNKNOWN.getCode(), CardRarity.Special, IPaperCard.DEFAULT_ART_INDEX));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -958,7 +959,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
System.err.println("We're sorry, but this card is not supported yet.");
|
||||
}
|
||||
|
||||
return new PaperCard(CardRules.getUnsupportedCardNamed(request.cardName), cardEdition.getCode(), cardRarity);
|
||||
return new PaperCard(CardRules.getUnsupportedCardNamed(request.cardName), cardEdition.getCode(), cardRarity, IPaperCard.DEFAULT_ART_INDEX);
|
||||
|
||||
}
|
||||
|
||||
@@ -1016,7 +1017,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
}
|
||||
}
|
||||
if (paperCards.isEmpty()) {
|
||||
paperCards.add(new PaperCard(rules, CardEdition.UNKNOWN.getCode(), CardRarity.Special));
|
||||
paperCards.add(new PaperCard(rules, CardEdition.UNKNOWN.getCode(), CardRarity.Special, IPaperCard.DEFAULT_ART_INDEX));
|
||||
}
|
||||
// 2. add them to db
|
||||
for (PaperCard paperCard : paperCards) {
|
||||
|
||||
@@ -163,11 +163,13 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
public final CardRarity rarity;
|
||||
public final String collectorNumber;
|
||||
public final String name;
|
||||
public final String artistName;
|
||||
|
||||
public CardInSet(final String name, final String collectorNumber, final CardRarity rarity) {
|
||||
public CardInSet(final String name, final String collectorNumber, final CardRarity rarity, final String artistName) {
|
||||
this.name = name;
|
||||
this.collectorNumber = collectorNumber;
|
||||
this.rarity = rarity;
|
||||
this.artistName = artistName;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
@@ -181,6 +183,10 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(name);
|
||||
if (artistName != null) {
|
||||
sb.append(" @");
|
||||
sb.append(artistName);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -535,7 +541,7 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
* name - grouping #5
|
||||
*/
|
||||
// "(^(.?[0-9A-Z]+.?))?(([SCURML]) )?(.*)$"
|
||||
"(^(.?[0-9A-Z]+\\S?[A-Z]*)\\s)?(([SCURML])\\s)?(.*)$"
|
||||
"(^(.?[0-9A-Z]+\\S?[A-Z]*)\\s)?(([SCURML])\\s)?([^@]*)( @(.*))?$"
|
||||
);
|
||||
|
||||
ListMultimap<String, CardInSet> cardMap = ArrayListMultimap.create();
|
||||
@@ -560,7 +566,8 @@ public final class CardEdition implements Comparable<CardEdition> {
|
||||
String collectorNumber = matcher.group(2);
|
||||
CardRarity r = CardRarity.smartValueOf(matcher.group(4));
|
||||
String cardName = matcher.group(5);
|
||||
CardInSet cis = new CardInSet(cardName, collectorNumber, r);
|
||||
String artistName = matcher.group(7);
|
||||
CardInSet cis = new CardInSet(cardName, collectorNumber, r, artistName);
|
||||
|
||||
cardMap.put(sectionName, cis);
|
||||
}
|
||||
|
||||
@@ -234,6 +234,7 @@ public interface IPaperCard extends InventoryItem, Serializable {
|
||||
boolean isToken();
|
||||
CardRules getRules();
|
||||
CardRarity getRarity();
|
||||
String getArtist();
|
||||
|
||||
String getItemType();
|
||||
|
||||
|
||||
@@ -17,7 +17,12 @@
|
||||
*/
|
||||
package forge.item;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.ImageKeys;
|
||||
import forge.StaticData;
|
||||
import forge.card.CardDb;
|
||||
@@ -28,10 +33,6 @@ import forge.util.CardTranslation;
|
||||
import forge.util.Localizer;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* A lightweight version of a card that matches real-world cards, to use outside of games (eg. inventory, decks, trade).
|
||||
* <br><br>
|
||||
@@ -53,9 +54,10 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
|
||||
(see getCollectorNumber())
|
||||
*/
|
||||
private String collectorNumber = null;
|
||||
private final String artist;
|
||||
private final int artIndex;
|
||||
private final boolean foil;
|
||||
private Boolean hasImage = null;
|
||||
private Boolean hasImage;
|
||||
|
||||
// Calculated fields are below:
|
||||
private transient CardRarity rarity; // rarity is given in ctor when set is assigned
|
||||
@@ -114,6 +116,11 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
|
||||
return rarity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArtist() {
|
||||
return artist;
|
||||
}
|
||||
|
||||
/* FIXME: At the moment, every card can get Foiled, with no restriction on the
|
||||
corresponding Edition - so we could Foil even Alpha cards.
|
||||
*/
|
||||
@@ -123,7 +130,7 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
|
||||
|
||||
if (this.foiledVersion == null) {
|
||||
this.foiledVersion = new PaperCard(this.rules, this.edition, this.rarity,
|
||||
this.artIndex, true, String.valueOf(collectorNumber));
|
||||
this.artIndex, true, String.valueOf(collectorNumber), this.artist);
|
||||
}
|
||||
return this.foiledVersion;
|
||||
}
|
||||
@@ -162,16 +169,12 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
|
||||
}
|
||||
};
|
||||
|
||||
public PaperCard(final CardRules rules0, final String edition0, final CardRarity rarity0) {
|
||||
this(rules0, edition0, rarity0, IPaperCard.DEFAULT_ART_INDEX, false);
|
||||
}
|
||||
|
||||
public PaperCard(final CardRules rules0, final String edition0, final CardRarity rarity0, final int artIndex0) {
|
||||
this(rules0, edition0, rarity0, artIndex0, false);
|
||||
this(rules0, edition0, rarity0, artIndex0, false, "");
|
||||
}
|
||||
|
||||
public PaperCard(final CardRules rules0, final String edition0, final CardRarity rarity0, final int artIndex0,
|
||||
final boolean foil0) {
|
||||
final boolean foil0, final String artist0) {
|
||||
if (rules0 == null || edition0 == null || rarity0 == null) {
|
||||
throw new IllegalArgumentException("Cannot create card without rules, edition or rarity");
|
||||
}
|
||||
@@ -181,16 +184,12 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
|
||||
artIndex = artIndex0 >= IPaperCard.DEFAULT_ART_INDEX ? artIndex0 : IPaperCard.DEFAULT_ART_INDEX;
|
||||
foil = foil0;
|
||||
rarity = rarity0;
|
||||
}
|
||||
|
||||
public PaperCard(final CardRules rules0, final String edition0, final CardRarity rarity0, final int artIndex0,
|
||||
final String collectorNumber0) {
|
||||
this(rules0, edition0, rarity0, artIndex0, false, collectorNumber0);
|
||||
artist = (artist0 != null ? artist0 : "");
|
||||
}
|
||||
|
||||
public PaperCard(final CardRules rules0, final String edition0, final CardRarity rarity0,
|
||||
final int artIndex0, final boolean foil0, final String collectorNumber0) {
|
||||
this(rules0, edition0, rarity0, artIndex0, foil0);
|
||||
final int artIndex0, final boolean foil0, final String collectorNumber0, final String artist) {
|
||||
this(rules0, edition0, rarity0, artIndex0, foil0, artist);
|
||||
if ((collectorNumber0 == null) || (collectorNumber0.length() == 0))
|
||||
collectorNumber = IPaperCard.NO_COLLECTOR_NUMBER;
|
||||
else
|
||||
|
||||
@@ -143,6 +143,7 @@ public class PaperToken implements InventoryItemFromSet, IPaperCard {
|
||||
@Override public CardRules getRules() { return card; }
|
||||
|
||||
@Override public CardRarity getRarity() { return CardRarity.None; }
|
||||
@Override public String getArtist() { /*TODO*/ return ""; }
|
||||
|
||||
// Unfortunately this is a property of token, cannot move it outside of class
|
||||
public String getImageFilename() { return getImageFilename(1); }
|
||||
|
||||
@@ -6,7 +6,6 @@ import forge.card.CardDb;
|
||||
import forge.card.CardRules;
|
||||
import forge.card.CardSplitType;
|
||||
import forge.item.PaperCard;
|
||||
import forge.item.PaperToken;
|
||||
|
||||
public class ImageUtil {
|
||||
public static float getNearestHQSize(float baseSize, float actualSize) {
|
||||
@@ -30,28 +29,6 @@ public class ImageUtil {
|
||||
return cp;
|
||||
}
|
||||
|
||||
public static PaperToken getPaperTokenFromImageKey(String key) {
|
||||
if ( key == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
key = key.substring(2);
|
||||
int index = key.lastIndexOf('_');
|
||||
if (index != -1) {
|
||||
String script = key.substring(0, index);
|
||||
String edition = key.substring(index + 1);
|
||||
if (script.startsWith("emblem"))
|
||||
return null;
|
||||
if (null == StaticData.instance().getCardEdition(edition)) {
|
||||
script = key;
|
||||
edition = "???";
|
||||
}
|
||||
script = script.replaceAll("[0-9]*$", "");
|
||||
return StaticData.instance().getAllTokens().getToken(script, edition);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getImageRelativePath(PaperCard cp, boolean backFace, boolean includeSet, boolean isDownloadUrl) {
|
||||
final String nameToUse = cp == null ? null : getNameToUse(cp, backFace);
|
||||
if (nameToUse == null) {
|
||||
@@ -78,7 +55,7 @@ public class ImageUtil {
|
||||
|
||||
int artIdx = cp.getArtIndex() - 1;
|
||||
if (hasManyPictures) {
|
||||
if ( cntPictures <= artIdx ) // prevent overflow
|
||||
if (cntPictures <= artIdx) // prevent overflow
|
||||
artIdx = cntPictures == 0 ? 0 : artIdx % cntPictures;
|
||||
s.append(artIdx + 1);
|
||||
}
|
||||
@@ -113,8 +90,8 @@ public class ImageUtil {
|
||||
|
||||
public static String getNameToUse(PaperCard cp, boolean backFace) {
|
||||
final CardRules card = cp.getRules();
|
||||
if (backFace ) {
|
||||
if ( hasBackFacePicture(cp) )
|
||||
if (backFace) {
|
||||
if (hasBackFacePicture(cp))
|
||||
if (card.getOtherPart() != null) {
|
||||
return card.getOtherPart().getName();
|
||||
} else if (!card.getMeldWith().isEmpty()) {
|
||||
@@ -140,7 +117,7 @@ public class ImageUtil {
|
||||
return getImageRelativePath(cp, backFace, true, true);
|
||||
}
|
||||
|
||||
public static String getScryfallDownloadUrl(PaperCard cp, boolean backFace, String setCode, String langCode){
|
||||
public static String getScryfallDownloadUrl(PaperCard cp, boolean backFace, String setCode, String langCode, boolean useArtCrop){
|
||||
String editionCode;
|
||||
if ((setCode != null) && (setCode.length() > 0))
|
||||
editionCode = setCode;
|
||||
@@ -149,12 +126,13 @@ public class ImageUtil {
|
||||
String cardCollectorNumber = cp.getCollectorNumber();
|
||||
// Hack to account for variations in Arabian Nights
|
||||
cardCollectorNumber = cardCollectorNumber.replace("+", "†");
|
||||
String versionParam = useArtCrop ? "art_crop" : "normal";
|
||||
String faceParam = "";
|
||||
if (cp.getRules().getOtherPart() != null) {
|
||||
faceParam = (backFace ? "&face=back" : "&face=front");
|
||||
}
|
||||
return String.format("%s/%s/%s?format=image&version=normal%s", editionCode, cardCollectorNumber,
|
||||
langCode, faceParam);
|
||||
return String.format("%s/%s/%s?format=image&version=%s%s", editionCode, cardCollectorNumber,
|
||||
langCode, versionParam, faceParam);
|
||||
}
|
||||
|
||||
public static String toMWSFilename(String in) {
|
||||
|
||||
@@ -1024,7 +1024,6 @@ public class Game {
|
||||
}
|
||||
|
||||
public void clearCaches() {
|
||||
|
||||
lastStateBattlefield.clear();
|
||||
lastStateGraveyard.clear();
|
||||
//playerCache.clear();
|
||||
|
||||
@@ -56,10 +56,10 @@ public class ChangeTargetsEffect extends SpellAbilityEffect {
|
||||
if (sa.hasParam("ChangeSingleTarget")) {
|
||||
// 1. choose a target of target spell
|
||||
List<Pair<SpellAbilityStackInstance, GameObject>> allTargets = new ArrayList<>();
|
||||
while(changingTgtSI != null) {
|
||||
while (changingTgtSI != null) {
|
||||
SpellAbility changedSa = changingTgtSI.getSpellAbility(true);
|
||||
if (changedSa.usesTargeting()) {
|
||||
for(GameObject it : changedSa.getTargets())
|
||||
for (GameObject it : changedSa.getTargets())
|
||||
allTargets.add(ImmutablePair.of(changingTgtSI, it));
|
||||
}
|
||||
changingTgtSI = changingTgtSI.getSubInstance();
|
||||
@@ -76,12 +76,14 @@ public class ChangeTargetsEffect extends SpellAbilityEffect {
|
||||
GameObject oldTarget = chosenTarget.getValue();
|
||||
TargetChoices oldTargetBlock = replaceIn.getTargetChoices();
|
||||
TargetChoices newTargetBlock = oldTargetBlock.clone();
|
||||
// gets the divied value from old target
|
||||
// gets the divided value from old target
|
||||
Integer div = oldTargetBlock.getDividedValue(oldTarget);
|
||||
// 3. test if updated choices would be correct.
|
||||
GameObject newTarget = Iterables.getFirst(getDefinedCardsOrTargeted(sa, "DefinedMagnet"), null);
|
||||
|
||||
if (replaceIn.getSpellAbility(true).canTarget(newTarget)) {
|
||||
// CR 115.3. The same target can’t be chosen multiple times for
|
||||
// any one instance of the word “target” on a spell or ability.
|
||||
if (!oldTargetBlock.contains(newTarget) && replaceIn.getSpellAbility(true).canTarget(newTarget)) {
|
||||
newTargetBlock.remove(oldTarget);
|
||||
newTargetBlock.add(newTarget);
|
||||
if (div != null) {
|
||||
@@ -89,9 +91,8 @@ public class ChangeTargetsEffect extends SpellAbilityEffect {
|
||||
}
|
||||
replaceIn.updateTarget(newTargetBlock, sa.getHostCard());
|
||||
}
|
||||
}
|
||||
else {
|
||||
while(changingTgtSI != null) {
|
||||
} else {
|
||||
while (changingTgtSI != null) {
|
||||
SpellAbility changingTgtSA = changingTgtSI.getSpellAbility(true);
|
||||
if (changingTgtSA.usesTargeting()) {
|
||||
// random target and DefinedMagnet works on single targets
|
||||
@@ -126,8 +127,7 @@ public class ChangeTargetsEffect extends SpellAbilityEffect {
|
||||
changingTgtSA.addDividedAllocation(newTarget, div);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Update targets, with a potential new target
|
||||
Predicate<GameObject> filter = sa.hasParam("TargetRestriction") ? GameObjectPredicates.restriction(sa.getParam("TargetRestriction").split(","), activator, sa.getHostCard(), sa) : null;
|
||||
// TODO Creature.Other might not work yet as it should
|
||||
|
||||
@@ -32,6 +32,12 @@ public class ChooseGenericEffect extends SpellAbilityEffect {
|
||||
final Card host = sa.getHostCard();
|
||||
|
||||
final List<SpellAbility> abilities = Lists.newArrayList(sa.getAdditionalAbilityList("Choices"));
|
||||
if (sa.hasParam("NumRandomChoices")) {
|
||||
int n = AbilityUtils.calculateAmount(host, sa.getParam("NumRandomChoices"), sa);
|
||||
while (abilities.size() > n) {
|
||||
Aggregates.removeRandom(abilities);
|
||||
}
|
||||
}
|
||||
final SpellAbility fallback = sa.getAdditionalAbility("FallbackAbility");
|
||||
final int amount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("ChoiceAmount", "1"), sa);
|
||||
|
||||
|
||||
@@ -124,8 +124,6 @@ public class EffectEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
String image;
|
||||
String set = hostCard.getSetCode().toLowerCase();
|
||||
StringBuilder imageSet = new StringBuilder();
|
||||
if (sa.hasParam("Image")) {
|
||||
image = ImageKeys.getTokenKey(sa.getParam("Image"));
|
||||
} else if (name.startsWith("Emblem")) { // try to get the image from name
|
||||
@@ -138,8 +136,6 @@ public class EffectEffect extends SpellAbilityEffect {
|
||||
} else { // use host image
|
||||
image = hostCard.getImageKey();
|
||||
}
|
||||
imageSet.append(image).append("_").append(set);
|
||||
image = imageSet.toString();
|
||||
|
||||
for (Player controller : effectOwner) {
|
||||
final Card eff = createEffect(sa, controller, name, image);
|
||||
|
||||
@@ -36,16 +36,25 @@ public class RevealEffect extends SpellAbilityEffect {
|
||||
}
|
||||
final CardCollection revealed = new CardCollection();
|
||||
if (sa.hasParam("Random")) {
|
||||
CardCollection valid = new CardCollection(cardsInHand);
|
||||
|
||||
if (sa.hasParam("RevealValid")) {
|
||||
valid = CardLists.getValidCards(valid, sa.getParam("RevealValid"), p, host, sa);
|
||||
}
|
||||
|
||||
if (valid.isEmpty())
|
||||
continue;
|
||||
|
||||
if (sa.hasParam("NumCards")) {
|
||||
final int revealnum = Math.min(cardsInHand.size(), cnt);
|
||||
final CardCollection hand = new CardCollection(cardsInHand);
|
||||
for (int i = 0; i < revealnum; i++) {
|
||||
final Card random = Aggregates.random(hand);
|
||||
final Card random = Aggregates.random(valid);
|
||||
revealed.add(random);
|
||||
hand.remove(random);
|
||||
valid.remove(random);
|
||||
}
|
||||
} else {
|
||||
revealed.add(Aggregates.random(cardsInHand));
|
||||
revealed.add(Aggregates.random(valid));
|
||||
}
|
||||
|
||||
} else if (sa.hasParam("RevealDefined")) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import forge.game.event.GameEventRollDie;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
@@ -75,6 +76,8 @@ public class RollDiceEffect extends SpellAbilityEffect {
|
||||
|
||||
for (int i = 0; i < amount; i++) {
|
||||
int roll = MyRandom.getRandom().nextInt(sides) + 1;
|
||||
// Play the die roll sound
|
||||
player.getGame().fireEvent(new GameEventRollDie());
|
||||
rolls.add(roll);
|
||||
total += roll;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package forge.game.ability.effects;
|
||||
import forge.game.Game;
|
||||
import forge.game.PlanarDice;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.event.GameEventRollDie;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
@@ -26,6 +27,8 @@ public class RollPlanarDiceEffect extends SpellAbilityEffect {
|
||||
game.getPhaseHandler().incPlanarDiceRolledthisTurn();
|
||||
}
|
||||
PlanarDice result = PlanarDice.roll(activator, null);
|
||||
// Play the die roll sound
|
||||
activator.getGame().fireEvent(new GameEventRollDie());
|
||||
String message = Localizer.getInstance().getMessage("lblPlayerRolledResult", activator.getName(), result.toString());
|
||||
game.getAction().notifyOfValue(sa, activator, message, null);
|
||||
|
||||
|
||||
@@ -27,6 +27,16 @@ import forge.card.CardDb.CardArtPreference;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostParser;
|
||||
import forge.game.*;
|
||||
import forge.game.CardTraitBase;
|
||||
import forge.game.Direction;
|
||||
import forge.game.EvenOdd;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameActionUtil;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.GameEntityCounterTable;
|
||||
import forge.game.GameStage;
|
||||
import forge.game.GlobalRuleChange;
|
||||
import forge.game.IHasSVars;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
@@ -2271,7 +2281,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
if (!stAb.isSecondary() && !stAb.isClassAbility()) {
|
||||
final String stAbD = stAb.toString();
|
||||
if (!stAbD.equals("")) {
|
||||
boolean disabled = getGame() != null && !stAb.checkConditions();
|
||||
boolean disabled = getGame() != null && getController() != null && game.getAge() != GameStage.Play && !stAb.checkConditions();
|
||||
if (disabled) sb.append(grayTag);
|
||||
sb.append(stAbD);
|
||||
if (disabled) sb.append(endTag);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package forge.game.event;
|
||||
|
||||
public class GameEventRollDie extends GameEvent {
|
||||
|
||||
@Override
|
||||
public <T> T visit(IGameEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ public interface IGameEventVisitor<T> {
|
||||
T visit(GameEventPlayerPoisoned event);
|
||||
T visit(GameEventPlayerPriority event);
|
||||
T visit(GameEventPlayerStatsChanged event);
|
||||
T visit(GameEventRollDie event);
|
||||
T visit(GameEventTokenStateUpdate event);
|
||||
T visit(GameEventScry event);
|
||||
T visit(GameEventShuffle event);
|
||||
@@ -88,6 +89,7 @@ public interface IGameEventVisitor<T> {
|
||||
public T visit(GameEventPlayerPoisoned event) { return null; }
|
||||
public T visit(GameEventPlayerPriority event) { return null; }
|
||||
public T visit(GameEventPlayerStatsChanged event) { return null; }
|
||||
public T visit(GameEventRollDie event) { return null; }
|
||||
public T visit(GameEventTokenStateUpdate event) { return null; }
|
||||
public T visit(GameEventScry event) { return null; }
|
||||
public T visit(GameEventShuffle event) { return null; }
|
||||
|
||||
@@ -413,33 +413,29 @@ public final class StaticAbilityContinuous {
|
||||
});
|
||||
}
|
||||
|
||||
if (layer == StaticAbilityLayer.TYPE && params.containsKey("RemoveType")) {
|
||||
removeTypes = Lists.newArrayList(Arrays.asList(params.get("RemoveType").split(" & ")));
|
||||
|
||||
Iterables.removeIf(removeTypes, new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
if (input.equals("ChosenType") && !hostCard.hasChosenType()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (layer == StaticAbilityLayer.TYPE) {
|
||||
if (params.containsKey("RemoveType")) {
|
||||
removeTypes = Lists.newArrayList(Arrays.asList(params.get("RemoveType").split(" & ")));
|
||||
|
||||
Iterables.removeIf(removeTypes, new Predicate<String>() {
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
if (input.equals("ChosenType") && !hostCard.hasChosenType()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (params.containsKey("RemoveSuperTypes")) {
|
||||
removeSuperTypes = true;
|
||||
}
|
||||
|
||||
if (params.containsKey("RemoveCardTypes")) {
|
||||
removeCardTypes = true;
|
||||
}
|
||||
|
||||
if (params.containsKey("RemoveSubTypes")) {
|
||||
removeSubTypes = true;
|
||||
}
|
||||
|
||||
if (params.containsKey("RemoveLandTypes")) {
|
||||
removeLandTypes = true;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.awt.RenderingHints;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
@@ -32,12 +33,14 @@ import java.util.concurrent.TimeUnit;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader.InvalidCacheLoadException;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.mortennobel.imagescaling.ResampleOp;
|
||||
|
||||
import forge.card.CardSplitType;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.PlayerView;
|
||||
@@ -54,6 +57,7 @@ import forge.toolbox.FSkin;
|
||||
import forge.toolbox.FSkin.SkinIcon;
|
||||
import forge.toolbox.imaging.FCardImageRenderer;
|
||||
import forge.util.ImageUtil;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
/**
|
||||
* This class stores ALL card images in a cache with soft values. this means
|
||||
@@ -150,8 +154,13 @@ public class ImageCache {
|
||||
*
|
||||
*/
|
||||
public static BufferedImage getOriginalImage(String imageKey, boolean useDefaultIfNotFound, CardView cardView) {
|
||||
return getOriginalImageInternal(imageKey, useDefaultIfNotFound, cardView).getLeft();
|
||||
}
|
||||
|
||||
// return the pair of image and a flag to indicate if it is a placeholder image.
|
||||
private static Pair<BufferedImage, Boolean> getOriginalImageInternal(String imageKey, boolean useDefaultIfNotFound, CardView cardView) {
|
||||
if (null == imageKey) {
|
||||
return null;
|
||||
return Pair.of(null, false);
|
||||
}
|
||||
|
||||
IPaperCard ipc = null;
|
||||
@@ -163,20 +172,44 @@ public class ImageCache {
|
||||
ipc = pc;
|
||||
imageKey = ImageUtil.getImageKey(pc, altState, true);
|
||||
if (StringUtils.isBlank(imageKey)) {
|
||||
return _defaultImage;
|
||||
return Pair.of(_defaultImage, true);
|
||||
}
|
||||
} else if (imageKey.startsWith(ImageKeys.TOKEN_PREFIX) && cardView != null && cardView.isToken()) {
|
||||
ipc = ImageUtil.getPaperTokenFromImageKey(imageKey);
|
||||
}
|
||||
|
||||
// Replace .full to .artcrop if art crop is preferred
|
||||
// Only allow use art if the artist info is available
|
||||
boolean useArtCrop = "Crop".equals(FModel.getPreferences().getPref(ForgePreferences.FPref.UI_CARD_ART_FORMAT))
|
||||
&& ipc != null && !ipc.getArtist().isEmpty();
|
||||
String originalKey = imageKey;
|
||||
if (useArtCrop) {
|
||||
if (ipc != null && ipc.getRules().getSplitType() == CardSplitType.Flip) {
|
||||
// Art crop will always use front face as image key for flip cards
|
||||
imageKey = ImageUtil.getImageKey((PaperCard) ipc, false, true);
|
||||
}
|
||||
imageKey = TextUtil.fastReplace(imageKey, ".full", ".artcrop");
|
||||
}
|
||||
|
||||
// Load from file and add to cache if not found in cache initially.
|
||||
BufferedImage original = getImage(imageKey);
|
||||
|
||||
if (original == null && !useDefaultIfNotFound) {
|
||||
return Pair.of(null, false);
|
||||
}
|
||||
|
||||
// if art crop is exist, check also if the full card image is also cached.
|
||||
if (useArtCrop && original != null) {
|
||||
BufferedImage cached = _CACHE.getIfPresent(originalKey);
|
||||
if (cached != null)
|
||||
return Pair.of(cached, false);
|
||||
}
|
||||
|
||||
boolean noBorder = !useArtCrop && !isPreferenceEnabled(ForgePreferences.FPref.UI_RENDER_BLACK_BORDERS);
|
||||
boolean fetcherEnabled = isPreferenceEnabled(ForgePreferences.FPref.UI_ENABLE_ONLINE_IMAGE_FETCHER);
|
||||
boolean isPlaceholder = (original == null) && fetcherEnabled;
|
||||
|
||||
// If the user has indicated that they prefer Forge NOT render a black border, round the image corners
|
||||
// to account for JPEG images that don't have a transparency.
|
||||
boolean noBorder = !isPreferenceEnabled(ForgePreferences.FPref.UI_RENDER_BLACK_BORDERS);
|
||||
if (original != null && noBorder) {
|
||||
|
||||
// use a quadratic equation to calculate the needed radius from an image dimension
|
||||
int radius;
|
||||
float width = original.getWidth();
|
||||
@@ -209,19 +242,28 @@ public class ImageCache {
|
||||
// No image file exists for the given key so optionally associate with
|
||||
// a default "not available" image, however do not add it to the cache,
|
||||
// as otherwise it's problematic to update if the real image gets fetched.
|
||||
if (original == null && useDefaultIfNotFound) {
|
||||
if (original == null || useArtCrop) {
|
||||
if (ipc != null || cardView != null) {
|
||||
int width = 488, height = 680;
|
||||
BufferedImage art = original;
|
||||
CardView card = ipc != null ? Card.getCardForUi(ipc).getView() : cardView;
|
||||
original = new BufferedImage(480, 680, BufferedImage.TYPE_INT_ARGB);
|
||||
FCardImageRenderer.drawCardImage(original.createGraphics(), card, altState, 480, 680);
|
||||
if (!isPreferenceEnabled(ForgePreferences.FPref.UI_ENABLE_ONLINE_IMAGE_FETCHER))
|
||||
_CACHE.put(imageKey, original);
|
||||
String legalString = null;
|
||||
original = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
if (art != null) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(StaticData.instance().getCardEdition(ipc.getEdition()).getDate());
|
||||
int year = cal.get(Calendar.YEAR);
|
||||
legalString = "Illus. " + ipc.getArtist() + " ©" + year + " WOTC";
|
||||
}
|
||||
FCardImageRenderer.drawCardImage(original.createGraphics(), card, altState, width, height, art, legalString);
|
||||
if (art != null || !fetcherEnabled)
|
||||
_CACHE.put(originalKey, original);
|
||||
} else {
|
||||
original = _defaultImage;
|
||||
}
|
||||
}
|
||||
|
||||
return original;
|
||||
return Pair.of(original, isPlaceholder);
|
||||
}
|
||||
|
||||
// cardView is for Emblem, since there is no paper card for them
|
||||
@@ -238,7 +280,9 @@ public class ImageCache {
|
||||
return cached;
|
||||
}
|
||||
|
||||
BufferedImage original = getOriginalImage(key, useDefaultImage, cardView);
|
||||
Pair<BufferedImage, Boolean> orgImgs = getOriginalImageInternal(key, useDefaultImage, cardView);
|
||||
BufferedImage original = orgImgs.getLeft();
|
||||
boolean isPlaceholder = orgImgs.getRight();
|
||||
if (original == null) { return null; }
|
||||
|
||||
if (original == _defaultImage) {
|
||||
@@ -274,7 +318,9 @@ public class ImageCache {
|
||||
result = resampler.filter(original, null);
|
||||
}
|
||||
|
||||
_CACHE.put(resizedKey, result);
|
||||
if (!isPlaceholder) {
|
||||
_CACHE.put(resizedKey, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
|
||||
@@ -541,7 +541,8 @@ public abstract class ACEditorBase<TItem extends InventoryItem, TModel extends D
|
||||
existingCard.getEdition(),
|
||||
existingCard.getRarity(),
|
||||
existingCard.getArtIndex(),
|
||||
true);
|
||||
true,
|
||||
existingCard.getArtist());
|
||||
// remove *quantity* instances of existing card
|
||||
CDeckEditorUI.SINGLETON_INSTANCE.removeSelectedCards(false, quantity);
|
||||
// add *quantity* into the deck and set them as selected
|
||||
|
||||
@@ -256,6 +256,7 @@ public enum CSubmenuPreferences implements ICDoc {
|
||||
initializeGameLogVerbosityComboBox();
|
||||
initializeCloseActionComboBox();
|
||||
initializeDefaultFontSizeComboBox();
|
||||
initializeCardArtFormatComboBox();
|
||||
initializeCardArtPreference();
|
||||
initializeAutoUpdaterComboBox();
|
||||
initializeMulliganRuleComboBox();
|
||||
@@ -447,6 +448,15 @@ public enum CSubmenuPreferences implements ICDoc {
|
||||
panel.setComboBox(comboBox, selectedItem);
|
||||
}
|
||||
|
||||
private void initializeCardArtFormatComboBox() {
|
||||
final String [] choices = {"Full", "Crop"};
|
||||
final FPref userSetting = FPref.UI_CARD_ART_FORMAT;
|
||||
final FComboBoxPanel<String> panel = this.view.getCbpCardArtFormatComboBoxPanel();
|
||||
final FComboBox<String> comboBox = createComboBox(choices, userSetting);
|
||||
final String selectedItem = this.prefs.getPref(userSetting);
|
||||
panel.setComboBox(comboBox, selectedItem);
|
||||
}
|
||||
|
||||
private void initializeAiProfilesComboBox() {
|
||||
final FPref userSetting = FPref.UI_CURRENT_AI_PROFILE;
|
||||
final FComboBoxPanel<String> panel = this.view.getAiProfilesComboBoxPanel();
|
||||
|
||||
@@ -124,6 +124,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
||||
private final FComboBoxPanel<GameLogEntryType> cbpGameLogEntryType = new FComboBoxPanel<>(localizer.getMessage("cbpGameLogEntryType")+":");
|
||||
private final FComboBoxPanel<CloseAction> cbpCloseAction = new FComboBoxPanel<>(localizer.getMessage("cbpCloseAction")+":");
|
||||
private final FComboBoxPanel<String> cbpDefaultFontSize = new FComboBoxPanel<>(localizer.getMessage("cbpDefaultFontSize")+":");
|
||||
private final FComboBoxPanel<String> cbpCardArtFormat = new FComboBoxPanel<>(localizer.getMessage("cbpCardArtFormat")+":");
|
||||
private final FComboBoxPanel<String> cbpCardArtPreference = new FComboBoxPanel<>(localizer.getMessage("lblPreferredArt")+":");
|
||||
private final FComboBoxPanel<String> cbpMulliganRule = new FComboBoxPanel<>(localizer.getMessage("cbpMulliganRule")+":");
|
||||
private final FComboBoxPanel<String> cbpAiProfiles = new FComboBoxPanel<>(localizer.getMessage("cbpAiProfiles")+":");
|
||||
@@ -331,6 +332,9 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
||||
pnlPrefs.add(cbpDefaultFontSize, comboBoxConstraints);
|
||||
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlDefaultFontSize")), descriptionConstraints);
|
||||
|
||||
pnlPrefs.add(cbpCardArtFormat, comboBoxConstraints);
|
||||
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlCardArtFormat")), descriptionConstraints);
|
||||
|
||||
pnlPrefs.add(cbImageFetcher, titleConstraints);
|
||||
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlImageFetcher")), descriptionConstraints);
|
||||
|
||||
@@ -764,6 +768,10 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
||||
return cbpDefaultFontSize;
|
||||
}
|
||||
|
||||
public FComboBoxPanel<String> getCbpCardArtFormatComboBoxPanel() {
|
||||
return cbpCardArtFormat;
|
||||
}
|
||||
|
||||
public FComboBoxPanel<String> getCbpDefaultLanguageComboBoxPanel() {
|
||||
return cbpDefaultLanguage;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import java.awt.Paint;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.text.BreakIterator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -37,16 +38,17 @@ import forge.util.CardTranslation;
|
||||
|
||||
public class FCardImageRenderer {
|
||||
private static boolean isInitialed = false;
|
||||
private static final float BASE_IMAGE_WIDTH = 480;
|
||||
private static final float BASE_IMAGE_WIDTH = 488;
|
||||
private static final float BASE_IMAGE_HEIGHT = 680;
|
||||
private static final float BLACK_BORDER_THICKNESS_RATIO = 0.021f;
|
||||
private static final float NAME_BOX_TINT = 0.2f;
|
||||
private static final float TEXT_BOX_TINT = 0.1f;
|
||||
private static final float PT_BOX_TINT = 0.2f;
|
||||
private static float CARD_ART_RATIO;
|
||||
private static int PT_BOX_WIDTH, HEADER_PADDING, TYPE_PADDING, BLACK_BORDER_THICKNESS, BORDER_THICKNESS;
|
||||
private static Font NAME_FONT, TYPE_FONT, TEXT_FONT, REMINDER_FONT, PT_FONT;
|
||||
private static int NAME_SIZE, TYPE_SIZE, TEXT_SIZE, REMINDER_SIZE, PT_SIZE;
|
||||
private static int PT_BOX_WIDTH, HEADER_PADDING, TYPE_PADDING, BLACK_BORDER_THICKNESS, BOX_LINE_THICKNESS;
|
||||
private static int ART_INSET, OUTER_BORDER_THICKNESS;
|
||||
private static Font NAME_FONT, TYPE_FONT, TEXT_FONT, REMINDER_FONT, PT_FONT, ARTIST_FONT;
|
||||
private static int NAME_SIZE, TYPE_SIZE, TEXT_SIZE, REMINDER_SIZE, PT_SIZE, ARTIST_SIZE;
|
||||
private static Map<Font, Font[]> cachedFonts;
|
||||
private static Color TEXT_COLOR;
|
||||
|
||||
private static BreakIterator boundary;
|
||||
@@ -54,7 +56,6 @@ public class FCardImageRenderer {
|
||||
private static Pattern reminderPattern;
|
||||
private static Pattern reminderHidePattern;
|
||||
private static Pattern symbolPattern;
|
||||
private static Map<Font, Font[]> shrinkFonts;
|
||||
|
||||
private static void initialize() {
|
||||
Locale locale = new Locale(FModel.getPreferences().getPref(FPref.UI_LANGUAGE));
|
||||
@@ -79,12 +80,14 @@ public class FCardImageRenderer {
|
||||
}
|
||||
}
|
||||
PT_FONT = NAME_FONT;
|
||||
ARTIST_FONT = new Font(Font.SERIF, Font.BOLD, 20);
|
||||
|
||||
shrinkFonts = new HashMap<>();
|
||||
shrinkFonts.put(NAME_FONT, new Font[NAME_FONT.getSize()]);
|
||||
shrinkFonts.put(TYPE_FONT, new Font[TYPE_FONT.getSize()]);
|
||||
shrinkFonts.put(TEXT_FONT, new Font[TEXT_FONT.getSize()]);
|
||||
shrinkFonts.put(REMINDER_FONT, new Font[REMINDER_FONT.getSize()]);
|
||||
cachedFonts = new HashMap<>();
|
||||
cachedFonts.put(NAME_FONT, new Font[NAME_FONT.getSize() * 2]);
|
||||
cachedFonts.put(TYPE_FONT, new Font[TYPE_FONT.getSize() * 2]);
|
||||
cachedFonts.put(TEXT_FONT, new Font[TEXT_FONT.getSize() * 2]);
|
||||
cachedFonts.put(REMINDER_FONT, new Font[REMINDER_FONT.getSize() * 2]);
|
||||
cachedFonts.put(ARTIST_FONT, new Font[ARTIST_FONT.getSize() * 2]);
|
||||
|
||||
isInitialed = true;
|
||||
}
|
||||
@@ -107,11 +110,11 @@ public class FCardImageRenderer {
|
||||
private static Color fromDetailColor(DetailColors detailColor) {
|
||||
return new Color(detailColor.r, detailColor.g, detailColor.b);
|
||||
}
|
||||
private static Color C_COMMON = fromDetailColor(DetailColors.COMMON);
|
||||
private static Color C_UNCOMMON = fromDetailColor(DetailColors.UNCOMMON);
|
||||
private static Color C_RARE = fromDetailColor(DetailColors.RARE);
|
||||
private static Color C_MYTHIC = fromDetailColor(DetailColors.MYTHIC);
|
||||
private static Color C_SPECIAL = fromDetailColor(DetailColors.SPECIAL);
|
||||
private static final Color C_COMMON = fromDetailColor(DetailColors.COMMON);
|
||||
private static final Color C_UNCOMMON = fromDetailColor(DetailColors.UNCOMMON);
|
||||
private static final Color C_RARE = fromDetailColor(DetailColors.RARE);
|
||||
private static final Color C_MYTHIC = fromDetailColor(DetailColors.MYTHIC);
|
||||
private static final Color C_SPECIAL = fromDetailColor(DetailColors.SPECIAL);
|
||||
private static Color getRarityColor(CardRarity rarity) {
|
||||
if (rarity == null)// NPE from Rarity weird...
|
||||
return Color.MAGENTA;
|
||||
@@ -129,122 +132,172 @@ public class FCardImageRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
private static Font getShrinkFont(Font orgFont, int newSize) {
|
||||
private static Font getFontBySize(Font orgFont, int newSize) {
|
||||
if (newSize == orgFont.getSize())
|
||||
return orgFont;
|
||||
Font font = shrinkFonts.get(orgFont)[newSize];
|
||||
Font font = cachedFonts.get(orgFont)[newSize];
|
||||
if (font == null) {
|
||||
font = orgFont.deriveFont((float)newSize);
|
||||
shrinkFonts.get(orgFont)[newSize] = font;
|
||||
cachedFonts.get(orgFont)[newSize] = font;
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
public static void drawCardImage(Graphics2D g, CardView card, boolean altState, int width, int height) {
|
||||
if (!isInitialed)
|
||||
initialize();
|
||||
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
float ratio = Math.min((float)width / BASE_IMAGE_WIDTH, (float)height / BASE_IMAGE_HEIGHT);
|
||||
TEXT_COLOR = Color.BLACK;
|
||||
if (card.isSplitCard()) {
|
||||
boolean needTranslation = !"en-US".equals(FModel.getPreferences().getPref(FPref.UI_LANGUAGE));
|
||||
final CardStateView leftState = card.getLeftSplitState();
|
||||
final String leftText = needTranslation ? CardTranslation.getTranslatedOracle(leftState.getName()) : leftState.getOracleText();
|
||||
final CardStateView rightState = card.getRightSplitState();
|
||||
String rightText = needTranslation ? CardTranslation.getTranslatedOracle(rightState.getName()) : rightState.getOracleText();
|
||||
boolean isAftermath = (rightState.getKeywordKey().contains("Aftermath"));
|
||||
if (isAftermath) {
|
||||
int halfHeight = Math.round(380 * ratio);
|
||||
int halfWidth = Math.round((halfHeight - 10) * ratio);
|
||||
CARD_ART_RATIO = 2.68f;
|
||||
updateAreaSizes(ratio, ratio);
|
||||
drawCardStateImage(g, leftState, leftText, width, halfHeight);
|
||||
CARD_ART_RATIO = 1.66f;
|
||||
g.translate((double) width, (double)halfWidth);
|
||||
g.rotate(Math.PI / 2.);
|
||||
drawCardStateImage(g, rightState, rightText, height - halfWidth, width);
|
||||
} else {
|
||||
CARD_ART_RATIO = 1.36f;
|
||||
updateAreaSizes(ratio, (float)height / 2f / (float)width);
|
||||
AffineTransform tf = g.getTransform();
|
||||
g.translate(0., (double)height);
|
||||
g.rotate(-Math.PI / 2.);
|
||||
drawCardStateImage(g, leftState, leftText, height / 2, width);
|
||||
g.setTransform(tf);
|
||||
g.translate(0., (double)height / 2);
|
||||
g.rotate(-Math.PI / 2.);
|
||||
drawCardStateImage(g, rightState, rightText, height / 2, width);
|
||||
}
|
||||
} else if (card.isFlipCard()) {
|
||||
boolean needTranslation = !card.isToken() || !(card.getCloneOrigin() == null);
|
||||
final CardStateView state = card.getState(altState);
|
||||
final String text = card.getText(state, needTranslation ? CardTranslation.getTranslationTexts(state.getName(), "") : null);
|
||||
final CardStateView flipState = card.getState(!altState);
|
||||
final String flipText = card.getText(flipState, needTranslation ? CardTranslation.getTranslationTexts(flipState.getName(), "") : null);
|
||||
CARD_ART_RATIO = 1.72f;
|
||||
updateAreaSizes(ratio, ratio);
|
||||
drawFlipCardImage(g, state, text, flipState, flipText, width, height, altState);
|
||||
} else if (card.isAdventureCard()) {
|
||||
boolean needTranslation = !card.isToken() || !(card.getCloneOrigin() == null);
|
||||
final CardStateView state = card.getState(false);
|
||||
final String text = card.getText(state, needTranslation ? CardTranslation.getTranslationTexts(state.getName(), "") : null);
|
||||
final CardStateView advState = card.getState(true);
|
||||
final String advText = card.getText(advState, needTranslation ? CardTranslation.getTranslationTexts(advState.getName(), "") : null);
|
||||
CARD_ART_RATIO = 1.32f;
|
||||
updateAreaSizes(ratio, ratio);
|
||||
drawAdvCardImage(g, state, text, advState, advText, width, height);
|
||||
} else {
|
||||
boolean needTranslation = !card.isToken() || !(card.getCloneOrigin() == null);
|
||||
final CardStateView state = card.getState(altState);
|
||||
final String text = card.getText(state, needTranslation ? CardTranslation.getTranslationTexts(state.getName(), "") : null);
|
||||
CARD_ART_RATIO = 1.32f;
|
||||
updateAreaSizes(ratio, ratio);
|
||||
drawCardStateImage(g, state, text, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateAreaSizes(float mainRatio, float subRatio) {
|
||||
NAME_SIZE = Math.round(NAME_FONT.getSize() * mainRatio);
|
||||
TYPE_SIZE = Math.round(TYPE_FONT.getSize() * subRatio);
|
||||
TEXT_SIZE = Math.round(TEXT_FONT.getSize() * mainRatio);
|
||||
REMINDER_SIZE = Math.round(REMINDER_FONT.getSize() * mainRatio);
|
||||
PT_SIZE = Math.round(PT_FONT.getSize() * mainRatio);
|
||||
ARTIST_SIZE = Math.round(ARTIST_FONT.getSize() * mainRatio);
|
||||
PT_BOX_WIDTH = Math.round(75 * mainRatio);
|
||||
HEADER_PADDING = Math.round(7 * mainRatio);
|
||||
TYPE_PADDING = Math.round(7 * subRatio) + (mainRatio == subRatio ? (NAME_SIZE - TYPE_SIZE) / 2 : 0);
|
||||
BORDER_THICKNESS = Math.max(Math.round(2 * mainRatio), 1);
|
||||
BOX_LINE_THICKNESS = Math.max(Math.round(2 * mainRatio), 1);
|
||||
BLACK_BORDER_THICKNESS = Math.round(10 * mainRatio);
|
||||
ART_INSET = Math.round(BLACK_BORDER_THICKNESS * 0.6f);
|
||||
OUTER_BORDER_THICKNESS = Math.round(1.2f * BLACK_BORDER_THICKNESS) - ART_INSET;
|
||||
}
|
||||
|
||||
private static void drawCardStateImage(Graphics2D g, CardStateView state, String text, int w, int h) {
|
||||
int x = 0, y = 0;
|
||||
public static void drawCardImage(Graphics2D g, CardView card, boolean altState, int width, int height, BufferedImage art, String legalString) {
|
||||
if (!isInitialed) {
|
||||
initialize();
|
||||
}
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||
float ratio = Math.min((float)width / BASE_IMAGE_WIDTH, (float)height / BASE_IMAGE_HEIGHT);
|
||||
BLACK_BORDER_THICKNESS = Math.round(10 * ratio);
|
||||
g.setColor(Color.BLACK);
|
||||
g.fillRect(x, y, w, h);
|
||||
x += BLACK_BORDER_THICKNESS;
|
||||
y += BLACK_BORDER_THICKNESS;
|
||||
w -= 2 * BLACK_BORDER_THICKNESS;
|
||||
h -= 2 * BLACK_BORDER_THICKNESS;
|
||||
g.fillRect(0, 0, width, height);
|
||||
|
||||
if (legalString != null) {
|
||||
TEXT_COLOR = Color.LIGHT_GRAY;
|
||||
int x = BLACK_BORDER_THICKNESS * 3;
|
||||
int y = height - BLACK_BORDER_THICKNESS * 3;
|
||||
int w = width;
|
||||
boolean hasPTBox = false;
|
||||
if (!card.isSplitCard() && !card.isFlipCard()) {
|
||||
final CardStateView state = card.getState(card.isAdventureCard() ? false : altState);
|
||||
if ((state.isCreature() && !state.getKeywordKey().contains("Level up"))
|
||||
|| state.isPlaneswalker() || state.getType().hasSubtype("Vehicle"))
|
||||
hasPTBox = true;
|
||||
}
|
||||
if (hasPTBox) {
|
||||
w -= PT_BOX_WIDTH + BLACK_BORDER_THICKNESS * 5;
|
||||
} else {
|
||||
w -= BLACK_BORDER_THICKNESS * 6;
|
||||
}
|
||||
int h = BLACK_BORDER_THICKNESS * 3;
|
||||
drawVerticallyCenteredString(g, legalString, new Rectangle(x, y, w, h), ARTIST_FONT, ARTIST_SIZE);
|
||||
}
|
||||
|
||||
width -= 2 * BLACK_BORDER_THICKNESS;
|
||||
height -= 2 * BLACK_BORDER_THICKNESS;
|
||||
g.translate(BLACK_BORDER_THICKNESS, BLACK_BORDER_THICKNESS);
|
||||
TEXT_COLOR = Color.BLACK;
|
||||
if (card.isSplitCard()) {
|
||||
boolean needTranslation = !"en-US".equals(FModel.getPreferences().getPref(FPref.UI_LANGUAGE));
|
||||
final CardStateView leftState = card.getLeftSplitState();
|
||||
final String leftText = needTranslation ? CardTranslation.getTranslatedOracle(leftState.getName()) : leftState.getOracleText();
|
||||
final CardStateView rightState = card.getRightSplitState();
|
||||
String rightText = needTranslation ? CardTranslation.getTranslatedOracle(rightState.getName()) : rightState.getOracleText();
|
||||
boolean isAftermath = (rightState.getKeywordKey().contains("Aftermath"));
|
||||
BufferedImage leftArt = null;
|
||||
BufferedImage rightArt = null;
|
||||
if (isAftermath) {
|
||||
if (art != null) {
|
||||
int leftWidth = Math.round(art.getWidth() * 0.61328125f);
|
||||
leftArt = art.getSubimage(0, 0, leftWidth, art.getHeight());
|
||||
rightArt = art.getSubimage(leftWidth, 0, art.getWidth() - leftWidth, art.getHeight());
|
||||
}
|
||||
int halfHeight = Math.round(370 * ratio);
|
||||
int halfWidth = Math.round(360 * ratio);
|
||||
CARD_ART_RATIO = 2.719f;
|
||||
updateAreaSizes(ratio, ratio);
|
||||
drawCardStateImage(g, leftState, leftText, width, halfHeight, leftArt);
|
||||
CARD_ART_RATIO = 1.714f;
|
||||
int widthAdjust = OUTER_BORDER_THICKNESS;
|
||||
int heightAdjust = OUTER_BORDER_THICKNESS + PT_SIZE / 2;
|
||||
g.translate((double) width - widthAdjust, (double)halfWidth);
|
||||
g.rotate(Math.PI / 2.);
|
||||
drawCardStateImage(g, rightState, rightText, height - halfWidth - heightAdjust, width, rightArt);
|
||||
} else {
|
||||
if (art != null) {
|
||||
leftArt = art.getSubimage(0, 0, art.getWidth() / 2, art.getHeight());
|
||||
rightArt = art.getSubimage(art.getWidth() / 2, 0, art.getWidth() / 2, art.getHeight());
|
||||
}
|
||||
CARD_ART_RATIO = 1.443f;
|
||||
updateAreaSizes(ratio, ((float)height / 2f / (float)width) * ratio);
|
||||
int widthAdjust = OUTER_BORDER_THICKNESS + PT_SIZE / 2;
|
||||
int heightAdjust = height - widthAdjust - BLACK_BORDER_THICKNESS;
|
||||
AffineTransform tf = g.getTransform();
|
||||
g.translate(0., (double)(height - widthAdjust));
|
||||
g.rotate(-Math.PI / 2.);
|
||||
drawCardStateImage(g, leftState, leftText, heightAdjust / 2, width + widthAdjust, leftArt);
|
||||
g.setTransform(tf);
|
||||
g.translate(0., (double)(heightAdjust / 2));
|
||||
g.rotate(-Math.PI / 2.);
|
||||
drawCardStateImage(g, rightState, rightText, heightAdjust / 2, width + widthAdjust, rightArt);
|
||||
}
|
||||
} else if (card.isFlipCard()) {
|
||||
boolean needTranslation = !card.isToken() || !(card.getCloneOrigin() == null);
|
||||
final CardStateView state = card.getState(false);
|
||||
final String text = card.getText(state, needTranslation ? CardTranslation.getTranslationTexts(state.getName(), "") : null);
|
||||
final CardStateView flipState = card.getState(true);
|
||||
final String flipText = card.getText(flipState, needTranslation ? CardTranslation.getTranslationTexts(flipState.getName(), "") : null);
|
||||
CARD_ART_RATIO = 1.728f;
|
||||
updateAreaSizes(ratio, ratio);
|
||||
int heightAdjust = OUTER_BORDER_THICKNESS + PT_SIZE / 2;
|
||||
if (altState) {
|
||||
g.translate(width, height);
|
||||
g.rotate(Math.PI);
|
||||
}
|
||||
drawFlipCardImage(g, state, text, flipState, flipText, width, height - heightAdjust, art);
|
||||
} else if (card.isAdventureCard()) {
|
||||
boolean needTranslation = !card.isToken() || !(card.getCloneOrigin() == null);
|
||||
final CardStateView state = card.getState(false);
|
||||
final String text = card.getText(state, needTranslation ? CardTranslation.getTranslationTexts(state.getName(), "") : null);
|
||||
final CardStateView advState = card.getState(true);
|
||||
final String advText = card.getText(advState, needTranslation ? CardTranslation.getTranslationTexts(advState.getName(), "") : null);
|
||||
CARD_ART_RATIO = 1.37f;
|
||||
updateAreaSizes(ratio, ratio);
|
||||
drawAdvCardImage(g, state, text, advState, advText, width, height, art);
|
||||
} else {
|
||||
boolean needTranslation = !card.isToken() || !(card.getCloneOrigin() == null);
|
||||
final CardStateView state = card.getState(altState);
|
||||
final String text = card.getText(state, needTranslation ? CardTranslation.getTranslationTexts(state.getName(), "") : null);
|
||||
CARD_ART_RATIO = 1.37f;
|
||||
if (art != null && Math.abs((float)art.getWidth() / (float)art.getHeight() - CARD_ART_RATIO) > 0.1f) {
|
||||
CARD_ART_RATIO = (float)art.getWidth() / (float)art.getHeight();
|
||||
}
|
||||
updateAreaSizes(ratio, ratio);
|
||||
drawCardStateImage(g, state, text, width, height, art);
|
||||
}
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
private static void drawCardStateImage(Graphics2D g, CardStateView state, String text, int w, int h, BufferedImage art) {
|
||||
int x = 0, y = 0;
|
||||
|
||||
//determine colors for borders
|
||||
final List<DetailColors> borderColors = CardDetailUtil.getBorderColors(state, true);
|
||||
Color[] colors = fillColorBackground(g, borderColors, x, y, w, h);
|
||||
Color[] colors = fillColorBackground(g, borderColors, x, y, w, h, BLACK_BORDER_THICKNESS);
|
||||
|
||||
int artInset = Math.round(BLACK_BORDER_THICKNESS * 0.8f);
|
||||
int outerBorderThickness = 2 * BLACK_BORDER_THICKNESS - artInset;
|
||||
x += outerBorderThickness;
|
||||
y += outerBorderThickness;
|
||||
w -= 2 * outerBorderThickness;
|
||||
x += OUTER_BORDER_THICKNESS;
|
||||
y += OUTER_BORDER_THICKNESS;
|
||||
w -= 2 * OUTER_BORDER_THICKNESS;
|
||||
int headerHeight = NAME_SIZE + 2 * HEADER_PADDING;
|
||||
int typeBoxHeight = TYPE_SIZE + 2 * TYPE_PADDING;
|
||||
int ptBoxHeight = 0;
|
||||
if (state.isCreature() || state.isPlaneswalker() || state.getType().hasSubtype("Vehicle")) {
|
||||
//if P/T box needed, make room for it
|
||||
ptBoxHeight = NAME_SIZE + HEADER_PADDING;
|
||||
ptBoxHeight = headerHeight;
|
||||
}
|
||||
|
||||
int artWidth = w - 2 * artInset;
|
||||
int artWidth = w - 2 * ART_INSET;
|
||||
int artHeight = Math.round(artWidth / CARD_ART_RATIO);
|
||||
int textBoxHeight = h - headerHeight - artHeight - typeBoxHeight - outerBorderThickness - artInset - PT_FONT.getSize() / 2;
|
||||
int textBoxHeight = h - headerHeight - artHeight - typeBoxHeight - OUTER_BORDER_THICKNESS - ART_INSET - PT_SIZE / 2;
|
||||
|
||||
int artY = y + headerHeight;
|
||||
int typeY = artY + artHeight;
|
||||
@@ -257,7 +310,7 @@ public class FCardImageRenderer {
|
||||
boolean isDungeon = state.getType().isDungeon();
|
||||
if (isSaga || isClass || isDungeon) {
|
||||
// Move type line to the bottom
|
||||
typeY = ptY - typeBoxHeight;
|
||||
typeY = ptY - Math.round(typeBoxHeight * 1.2f);
|
||||
if (!isDungeon)
|
||||
artWidth = artWidth / 2;
|
||||
artHeight = typeY - artY;
|
||||
@@ -268,8 +321,8 @@ public class FCardImageRenderer {
|
||||
//draw art box with Forge icon
|
||||
if (!isDungeon) {
|
||||
Color[] artBoxColors = tintColors(Color.DARK_GRAY, colors, NAME_BOX_TINT);
|
||||
int artX = x + artInset + (isSaga ? artWidth : 0);
|
||||
drawArt(g, artBoxColors, artX, artY, artWidth, artHeight);
|
||||
int artX = x + ART_INSET + (isSaga ? artWidth : 0);
|
||||
drawArt(g, artBoxColors, artX, artY, artWidth, artHeight, art);
|
||||
}
|
||||
|
||||
//handle leveler cards
|
||||
@@ -320,7 +373,7 @@ public class FCardImageRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
int textX = x + artInset;
|
||||
int textX = x + ART_INSET;
|
||||
|
||||
//draw text box
|
||||
Color[] textBox1Colors = tintColors(Color.WHITE, colors, TEXT_BOX_TINT);
|
||||
@@ -364,7 +417,7 @@ public class FCardImageRenderer {
|
||||
} else {
|
||||
//draw text box
|
||||
Color[] textBoxColors = tintColors(Color.WHITE, colors, TEXT_BOX_TINT);
|
||||
int textX = x + artInset + (isClass ? artWidth : 0);
|
||||
int textX = x + ART_INSET + (isClass ? artWidth : 0);
|
||||
drawTextBox(g, state, text, textBoxColors, textX, textY, artWidth, textBoxHeight, ptBoxHeight > 0 ? 1 : 0);
|
||||
|
||||
//draw P/T box
|
||||
@@ -377,63 +430,53 @@ public class FCardImageRenderer {
|
||||
|
||||
//draw header containing name and mana cost
|
||||
Color[] headerColors = tintColors(Color.WHITE, colors, NAME_BOX_TINT);
|
||||
drawHeader(g, state, headerColors, x, y, w, headerHeight, true);
|
||||
drawHeader(g, state, headerColors, x, y, w, headerHeight, true, true);
|
||||
|
||||
//draw type line
|
||||
drawTypeLine(g, state, headerColors, x, typeY, w, typeBoxHeight, 0, true);
|
||||
drawTypeLine(g, state, headerColors, x, typeY, w, typeBoxHeight, 0, true, true);
|
||||
}
|
||||
|
||||
private static void drawFlipCardImage(Graphics2D g, CardStateView state, String text, CardStateView flipState, String flipText, int w, int h, boolean isFlipped) {
|
||||
private static void drawFlipCardImage(Graphics2D g, CardStateView state, String text, CardStateView flipState, String flipText, int w, int h, BufferedImage art) {
|
||||
int width = w, height = h;
|
||||
int x = 0, y = 0;
|
||||
g.setColor(Color.BLACK);
|
||||
g.fillRect(x, y, w, h);
|
||||
x += BLACK_BORDER_THICKNESS;
|
||||
y += BLACK_BORDER_THICKNESS;
|
||||
w -= 2 * BLACK_BORDER_THICKNESS;
|
||||
h -= 2 * BLACK_BORDER_THICKNESS;
|
||||
|
||||
//determine colors for borders
|
||||
final List<DetailColors> borderColors = CardDetailUtil.getBorderColors(state, true);
|
||||
Color[] colors = fillColorBackground(g, borderColors, x, y, w, h);
|
||||
Color[] colors = fillColorBackground(g, borderColors, x, y, w, h, 0);
|
||||
|
||||
int artInset = Math.round(BLACK_BORDER_THICKNESS * 0.8f);
|
||||
int outerBorderThickness = 2 * BLACK_BORDER_THICKNESS - artInset;
|
||||
x += outerBorderThickness;
|
||||
y += outerBorderThickness;
|
||||
w -= 2 * outerBorderThickness;
|
||||
h -= 2 * outerBorderThickness;
|
||||
x += OUTER_BORDER_THICKNESS;
|
||||
y += OUTER_BORDER_THICKNESS;
|
||||
w -= 2 * OUTER_BORDER_THICKNESS;
|
||||
h -= 2 * OUTER_BORDER_THICKNESS;
|
||||
int headerHeight = NAME_SIZE + 2 * HEADER_PADDING;
|
||||
int typeBoxHeight = TYPE_SIZE + 2 * TYPE_PADDING;
|
||||
|
||||
int artWidth = w - 2 * artInset;
|
||||
int artWidth = w - 2 * ART_INSET;
|
||||
int artHeight = Math.round(artWidth / CARD_ART_RATIO);
|
||||
int textBoxHeight = (h - (headerHeight + typeBoxHeight) * 2 - artHeight) / 2;
|
||||
int ptBoxHeight = NAME_SIZE + HEADER_PADDING;
|
||||
int ptBoxHeight = headerHeight;
|
||||
|
||||
int textY = y + headerHeight;
|
||||
int typeY = textY + textBoxHeight;
|
||||
int artY = typeY + typeBoxHeight;
|
||||
int ptY = typeY - 4;
|
||||
int ptY = typeY + 1;
|
||||
|
||||
//draw art box with Forge icon
|
||||
if (!isFlipped) {
|
||||
Color[] artBoxColors = tintColors(Color.DARK_GRAY, colors, NAME_BOX_TINT);
|
||||
int artX = x + artInset;
|
||||
drawArt(g, artBoxColors, artX, artY, artWidth, artHeight);
|
||||
}
|
||||
Color[] artBoxColors = tintColors(Color.DARK_GRAY, colors, NAME_BOX_TINT);
|
||||
int artX = x + ART_INSET;
|
||||
drawArt(g, artBoxColors, artX, artY, artWidth, artHeight, art);
|
||||
|
||||
//draw text box
|
||||
Color[] textBoxColors = tintColors(Color.WHITE, colors, TEXT_BOX_TINT);
|
||||
int textX = x + artInset;
|
||||
int textX = x + ART_INSET;
|
||||
drawTextBox(g, state, text, textBoxColors, textX, textY, artWidth, textBoxHeight, 0);
|
||||
|
||||
//draw header containing name and mana cost
|
||||
Color[] headerColors = tintColors(Color.WHITE, colors, NAME_BOX_TINT);
|
||||
drawHeader(g, state, headerColors, x, y, w, headerHeight, !isFlipped);
|
||||
drawHeader(g, state, headerColors, x, y, w, headerHeight, true, true);
|
||||
|
||||
//draw type line
|
||||
drawTypeLine(g, state, headerColors, x, typeY, w, typeBoxHeight, state.isCreature() ? PT_BOX_WIDTH : 0, !isFlipped);
|
||||
drawTypeLine(g, state, headerColors, x, typeY, w, typeBoxHeight, state.isCreature() ? PT_BOX_WIDTH : 0, true, true);
|
||||
|
||||
//draw P/T box
|
||||
if (state.isCreature()) {
|
||||
@@ -445,21 +488,14 @@ public class FCardImageRenderer {
|
||||
g.translate(width, height);
|
||||
g.rotate(Math.PI);
|
||||
|
||||
//draw art box with Forge icon
|
||||
if (isFlipped) {
|
||||
Color[] artBoxColors = tintColors(Color.DARK_GRAY, colors, NAME_BOX_TINT);
|
||||
int artX = x + artInset;
|
||||
drawArt(g, artBoxColors, artX, artY, artWidth, artHeight);
|
||||
}
|
||||
|
||||
//draw text box
|
||||
drawTextBox(g, flipState, flipText, textBoxColors, textX, textY, artWidth, textBoxHeight, 0);
|
||||
|
||||
//draw header containing name and mana cost
|
||||
drawHeader(g, flipState, headerColors, x, y, w, headerHeight, isFlipped);
|
||||
drawHeader(g, flipState, headerColors, x, y, w, headerHeight, false, true);
|
||||
|
||||
//draw type line
|
||||
drawTypeLine(g, flipState, headerColors, x, typeY, w, typeBoxHeight, flipState.isCreature() ? PT_BOX_WIDTH : 0, isFlipped);
|
||||
drawTypeLine(g, flipState, headerColors, x, typeY, w, typeBoxHeight, flipState.isCreature() ? PT_BOX_WIDTH : 0, false, true);
|
||||
|
||||
//draw P/T box
|
||||
if (flipState.isCreature()) {
|
||||
@@ -468,32 +504,24 @@ public class FCardImageRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
private static void drawAdvCardImage(Graphics2D g, CardStateView state, String text, CardStateView advState, String advText, int w, int h) {
|
||||
private static void drawAdvCardImage(Graphics2D g, CardStateView state, String text, CardStateView advState, String advText, int w, int h, BufferedImage art) {
|
||||
int x = 0, y = 0;
|
||||
g.setColor(Color.BLACK);
|
||||
g.fillRect(x, y, w, h);
|
||||
x += BLACK_BORDER_THICKNESS;
|
||||
y += BLACK_BORDER_THICKNESS;
|
||||
w -= 2 * BLACK_BORDER_THICKNESS;
|
||||
h -= 2 * BLACK_BORDER_THICKNESS;
|
||||
|
||||
//determine colors for borders
|
||||
final List<DetailColors> borderColors = CardDetailUtil.getBorderColors(state, true);
|
||||
Color[] colors = fillColorBackground(g, borderColors, x, y, w, h);
|
||||
Color[] colors = fillColorBackground(g, borderColors, x, y, w, h, BLACK_BORDER_THICKNESS);
|
||||
|
||||
int artInset = Math.round(BLACK_BORDER_THICKNESS * 0.8f);
|
||||
int outerBorderThickness = 2 * BLACK_BORDER_THICKNESS - artInset;
|
||||
x += outerBorderThickness;
|
||||
y += outerBorderThickness;
|
||||
w -= 2 * outerBorderThickness;
|
||||
x += OUTER_BORDER_THICKNESS;
|
||||
y += OUTER_BORDER_THICKNESS;
|
||||
w -= 2 * OUTER_BORDER_THICKNESS;
|
||||
int headerHeight = NAME_SIZE + 2 * HEADER_PADDING;
|
||||
int typeBoxHeight = TYPE_SIZE + 2 * TYPE_PADDING;
|
||||
int ptBoxHeight = NAME_SIZE + HEADER_PADDING;
|
||||
int ptBoxHeight = headerHeight;
|
||||
|
||||
int artWidth = w - 2 * artInset;
|
||||
int artWidth = w - 2 * ART_INSET;
|
||||
int artHeight = Math.round(artWidth / CARD_ART_RATIO);
|
||||
int textBoxWidth = artWidth / 2;
|
||||
int textBoxHeight = h - headerHeight - artHeight - typeBoxHeight - outerBorderThickness - artInset - PT_FONT.getSize() / 2;
|
||||
int textBoxHeight = h - headerHeight - artHeight - typeBoxHeight - OUTER_BORDER_THICKNESS - ART_INSET - PT_SIZE / 2;
|
||||
|
||||
int artY = y + headerHeight;
|
||||
int typeY = artY + artHeight;
|
||||
@@ -502,20 +530,20 @@ public class FCardImageRenderer {
|
||||
|
||||
//draw art box with Forge icon
|
||||
Color[] artBoxColors = tintColors(Color.DARK_GRAY, colors, NAME_BOX_TINT);
|
||||
int artX = x + artInset;
|
||||
drawArt(g, artBoxColors, artX, artY, artWidth, artHeight);
|
||||
int artX = x + ART_INSET;
|
||||
drawArt(g, artBoxColors, artX, artY, artWidth, artHeight, art);
|
||||
|
||||
//draw text box
|
||||
Color[] textBoxColors = tintColors(Color.WHITE, colors, TEXT_BOX_TINT);
|
||||
int textX = x + artInset + textBoxWidth;
|
||||
int textX = x + ART_INSET + textBoxWidth;
|
||||
drawTextBox(g, state, text, textBoxColors, textX, textY, textBoxWidth, textBoxHeight, 1);
|
||||
|
||||
//draw header containing name and mana cost
|
||||
Color[] headerColors = tintColors(Color.WHITE, colors, NAME_BOX_TINT);
|
||||
drawHeader(g, state, headerColors, x, y, w, headerHeight, true);
|
||||
drawHeader(g, state, headerColors, x, y, w, headerHeight, true, true);
|
||||
|
||||
//draw type line
|
||||
drawTypeLine(g, state, headerColors, x, typeY, w, typeBoxHeight, 0, true);
|
||||
drawTypeLine(g, state, headerColors, x, typeY, w, typeBoxHeight, 0, true, true);
|
||||
|
||||
//draw P/T box
|
||||
Color[] ptColors = tintColors(Color.WHITE, colors, PT_BOX_TINT);
|
||||
@@ -525,32 +553,31 @@ public class FCardImageRenderer {
|
||||
int advTypeHeight = advHeaderHeight - 1;
|
||||
NAME_SIZE = TYPE_SIZE - 2;
|
||||
TYPE_SIZE = NAME_SIZE - 1;
|
||||
textX = x + artInset;
|
||||
textX = x + ART_INSET;
|
||||
|
||||
//draw header containing name and mana cost
|
||||
Color[] advheaderColors = tintColors(Color.GRAY, colors, 0.6f);
|
||||
TEXT_COLOR = Color.WHITE;
|
||||
drawHeader(g, advState, advheaderColors, textX, textY, textBoxWidth, advHeaderHeight, true);
|
||||
drawHeader(g, advState, advheaderColors, textX, textY, textBoxWidth, advHeaderHeight, true, false);
|
||||
|
||||
//draw type line
|
||||
Color[] advTypeColors = tintColors(Color.DARK_GRAY, colors, 0.6f);
|
||||
textY += advHeaderHeight;
|
||||
drawTypeLine(g, advState, advTypeColors, textX, textY, textBoxWidth, advTypeHeight, 0, false);
|
||||
drawTypeLine(g, advState, advTypeColors, textX, textY + advHeaderHeight, textBoxWidth, advTypeHeight, 0, false, false);
|
||||
|
||||
//draw text box
|
||||
TEXT_COLOR = Color.BLACK;
|
||||
textY += advTypeHeight;
|
||||
textBoxHeight -= advHeaderHeight + advTypeHeight;
|
||||
drawTextBox(g, advState, advText, textBoxColors, textX, textY, textBoxWidth, textBoxHeight, 0);
|
||||
int yAdjust = advHeaderHeight + advTypeHeight;
|
||||
drawTextBox(g, advState, advText, textBoxColors, textX, textY, textBoxWidth, textBoxHeight, (yAdjust << 16));
|
||||
}
|
||||
|
||||
private static Color[] fillColorBackground(Graphics2D g, List<DetailColors> backColors, int x, int y, int w, int h) {
|
||||
private static Color[] fillColorBackground(Graphics2D g, List<DetailColors> backColors, int x, int y, int w, int h, int borderThickness) {
|
||||
Color[] colors = new Color[backColors.size()];
|
||||
for (int i = 0; i < colors.length; i++) {
|
||||
DetailColors dc = backColors.get(i);
|
||||
colors[i] = new Color(dc.r, dc.g, dc.b);
|
||||
}
|
||||
fillColorBackground(g, colors, x, y, w, h);
|
||||
fillRoundColorBackground(g, colors, x, y, w, h - 2 * borderThickness, borderThickness * 12, borderThickness * 10);
|
||||
fillColorBackground(g, colors, x, y, w, 10 * borderThickness);
|
||||
return colors;
|
||||
}
|
||||
private static void fillColorBackground(Graphics2D g, Color[] colors, float x, float y, float w, float h) {
|
||||
@@ -577,15 +604,39 @@ public class FCardImageRenderer {
|
||||
}
|
||||
g.setPaint(oldPaint);
|
||||
}
|
||||
private static void fillRoundColorBackground(Graphics2D g, Color[] colors, float x, float y, float w, float h, float arcWidth, float arcHeight) {
|
||||
Paint oldPaint = g.getPaint();
|
||||
switch (colors.length) {
|
||||
case 1:
|
||||
g.setColor(colors[0]);
|
||||
g.fillRoundRect(Math.round(x), Math.round(y), Math.round(w), Math.round(h), Math.round(arcWidth), Math.round(arcHeight));
|
||||
break;
|
||||
case 2:
|
||||
GradientPaint gradient = new GradientPaint(x, y, colors[0], x + w, y, colors[1]);
|
||||
g.setPaint(gradient);
|
||||
g.fillRoundRect(Math.round(x), Math.round(y), Math.round(w), Math.round(h), Math.round(arcWidth), Math.round(arcHeight));
|
||||
break;
|
||||
case 3:
|
||||
float halfWidth = w / 2;
|
||||
GradientPaint gradient1 = new GradientPaint(x, y, colors[0], x + halfWidth, y, colors[1]);
|
||||
g.setPaint(gradient1);
|
||||
g.fillRoundRect(Math.round(x), Math.round(y), Math.round(halfWidth + arcWidth), Math.round(h), Math.round(arcWidth), Math.round(arcHeight));
|
||||
GradientPaint gradient2 = new GradientPaint(x + halfWidth, y, colors[1], x + w, y, colors[2]);
|
||||
g.setPaint(gradient2);
|
||||
g.fillRoundRect(Math.round(x + halfWidth - arcWidth), Math.round(y), Math.round(halfWidth + arcWidth), Math.round(h), Math.round(arcWidth), Math.round(arcHeight));
|
||||
break;
|
||||
}
|
||||
g.setPaint(oldPaint);
|
||||
}
|
||||
|
||||
private static void drawVerticallyCenteredString(Graphics2D g, String text, Rectangle area, Font originalFont, int size) {
|
||||
Font font = getShrinkFont(originalFont, size);
|
||||
Font font = getFontBySize(originalFont, size);
|
||||
FontMetrics fontMetrics = g.getFontMetrics(font);
|
||||
|
||||
// Shrink font if the text is too long
|
||||
while (fontMetrics.stringWidth(text) > area.width) {
|
||||
--size;
|
||||
font = getShrinkFont(originalFont, size);
|
||||
font = getFontBySize(originalFont, size);
|
||||
fontMetrics = g.getFontMetrics(font);
|
||||
}
|
||||
|
||||
@@ -597,19 +648,20 @@ public class FCardImageRenderer {
|
||||
g.drawString(text, x, y);
|
||||
}
|
||||
|
||||
private static void drawHeader(Graphics2D g, CardStateView state, Color[] colors, int x, int y, int w, int h, boolean drawMana) {
|
||||
fillColorBackground(g, colors, x, y, w, h);
|
||||
g.setStroke(new BasicStroke(BORDER_THICKNESS));
|
||||
g.setColor(Color.BLACK);
|
||||
g.drawRect(x, y, w, h);
|
||||
|
||||
int padding = h / 4;
|
||||
private static void drawHeader(Graphics2D g, CardStateView state, Color[] colors, int x, int y, int w, int h, boolean drawMana, boolean drawRoundRect) {
|
||||
int padding = h / 3;
|
||||
fillRoundColorBackground(g, colors, x, y, w, h, drawRoundRect ? padding : 0, drawRoundRect ? h : 0);
|
||||
if (drawRoundRect) {
|
||||
g.setStroke(new BasicStroke(BOX_LINE_THICKNESS));
|
||||
g.setColor(Color.BLACK);
|
||||
g.drawRoundRect(x, y, w, h, padding, h);
|
||||
}
|
||||
|
||||
//draw mana cost for card
|
||||
if (drawMana) {
|
||||
ManaCost manaCost = state.getManaCost();
|
||||
int manaCostWidth = manaCost.getGlyphCount() * NAME_SIZE + HEADER_PADDING;
|
||||
CardFaceSymbols.draw(g, manaCost, x + w - manaCostWidth, y + (h - NAME_SIZE) / 2 + 1, NAME_SIZE);
|
||||
CardFaceSymbols.draw(g, manaCost, x + w - manaCostWidth, y + (h - NAME_SIZE) / 2 + 1, NAME_SIZE - 1);
|
||||
w -= padding + manaCostWidth;
|
||||
}
|
||||
|
||||
@@ -621,31 +673,47 @@ public class FCardImageRenderer {
|
||||
}
|
||||
|
||||
|
||||
private static void drawArt(Graphics2D g, Color[] colors, int x, int y, int w, int h) {
|
||||
fillColorBackground(g, colors, x, y, w, h);
|
||||
SkinIcon art = FSkin.getIcon(FSkinProp.ICO_LOGO);
|
||||
float artWidth = (float)art.getSizeForPaint(g).getWidth();
|
||||
float artHeight = (float)art.getSizeForPaint(g).getHeight();
|
||||
if (artWidth / artHeight >= (float)w / (float)h) {
|
||||
int newH = Math.round(w * (artHeight / artWidth));
|
||||
FSkin.drawImage(g, art, x, y + (h - newH) / 2, w, newH);
|
||||
private static void drawArt(Graphics2D g, Color[] colors, int x, int y, int w, int h, BufferedImage art) {
|
||||
if (art != null) {
|
||||
int artWidth = art.getWidth();
|
||||
int artHeight = art.getHeight();
|
||||
if ((float)artWidth / (float)artHeight >= (float)w / (float)h) {
|
||||
int newW = Math.round(artHeight * ((float)w / (float)h));
|
||||
int newX = (artWidth - newW) / 2;
|
||||
g.drawImage(art, x, y, x + w, y + h, newX, 0, newX + newW, art.getHeight(), null);
|
||||
} else {
|
||||
int newH = Math.round(artWidth * ((float)h / (float)w));
|
||||
int newY = (artHeight - newH) / 2;
|
||||
g.drawImage(art, x, y, x + w, y + h, 0, newY, art.getWidth(), newY + newH, null);
|
||||
}
|
||||
} else {
|
||||
int newW = Math.round(h * (artWidth / artHeight));
|
||||
FSkin.drawImage(g, art, x + (w - newW) / 2, y, newW, h);
|
||||
fillColorBackground(g, colors, x, y, w, h);
|
||||
SkinIcon icon = FSkin.getIcon(FSkinProp.ICO_LOGO);
|
||||
float artWidth = (float)icon.getSizeForPaint(g).getWidth();
|
||||
float artHeight = (float)icon.getSizeForPaint(g).getHeight();
|
||||
if (artWidth / artHeight >= (float)w / (float)h) {
|
||||
int newH = Math.round(w * (artHeight / artWidth));
|
||||
FSkin.drawImage(g, icon, x, y + (h - newH) / 2, w, newH);
|
||||
} else {
|
||||
int newW = Math.round(h * (artWidth / artHeight));
|
||||
FSkin.drawImage(g, icon, x + (w - newW) / 2, y, newW, h);
|
||||
}
|
||||
}
|
||||
g.setStroke(new BasicStroke(BORDER_THICKNESS));
|
||||
g.setStroke(new BasicStroke(BOX_LINE_THICKNESS));
|
||||
g.setColor(Color.BLACK);
|
||||
g.drawRect(x, y, w, h);
|
||||
}
|
||||
|
||||
private static void drawTypeLine(Graphics2D g, CardStateView state, Color[] colors, int x, int y, int w, int h, int adjust, boolean drawRarity) {
|
||||
fillColorBackground(g, colors, x, y, w, h);
|
||||
g.setStroke(new BasicStroke(BORDER_THICKNESS));
|
||||
g.setColor(Color.BLACK);
|
||||
g.drawRect(x, y, w, h);
|
||||
private static void drawTypeLine(Graphics2D g, CardStateView state, Color[] colors, int x, int y, int w, int h, int adjust, boolean drawRarity, boolean drawRoundRect) {
|
||||
int padding = h / 3;
|
||||
fillRoundColorBackground(g, colors, x, y, w, h, drawRoundRect ? padding : 0, drawRoundRect ? h : 0);
|
||||
if (drawRoundRect) {
|
||||
g.setStroke(new BasicStroke(BOX_LINE_THICKNESS));
|
||||
g.setColor(Color.BLACK);
|
||||
g.drawRoundRect(x, y, w, h, padding, h);
|
||||
}
|
||||
|
||||
w -= adjust;
|
||||
int padding = h / 4;
|
||||
|
||||
//draw square icon for rarity
|
||||
if (drawRarity) {
|
||||
@@ -653,7 +721,7 @@ public class FCardImageRenderer {
|
||||
int iconPadding = (h - iconSize) / 2;
|
||||
w -= iconSize + iconPadding * 2;
|
||||
g.setColor(getRarityColor(state.getRarity()));
|
||||
g.fillRect(x + w + iconPadding, y + (h - iconSize) / 2, iconSize, iconSize);
|
||||
g.fillRect(x + w + iconPadding, y + (h - iconSize + 1) / 2, iconSize, iconSize);
|
||||
}
|
||||
|
||||
//draw type
|
||||
@@ -664,12 +732,13 @@ public class FCardImageRenderer {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param flagPTBox [0] bit: has PT box, [1] bit: leveler PT box, [2] bit: leveler Level box
|
||||
* @param textBoxFlags [0] bit: has PT box, [1] bit: leveler PT box, [2] bit: leveler Level box, [16~31] bit: y adjust
|
||||
*/
|
||||
private static void drawTextBox(Graphics2D g, CardStateView state, String text, Color[] colors,
|
||||
int x, int y, int w, int h, int flagPTBox) {
|
||||
fillColorBackground(g, colors, x, y, w, h);
|
||||
g.setStroke(new BasicStroke(BORDER_THICKNESS));
|
||||
int x, int y, int w, int h, int textBoxFlags) {
|
||||
int yAdjust = (textBoxFlags >> 16);
|
||||
fillColorBackground(g, colors, x, y + yAdjust, w, h - yAdjust);
|
||||
g.setStroke(new BasicStroke(BOX_LINE_THICKNESS));
|
||||
g.setColor(Color.BLACK);
|
||||
g.drawRect(x, y, w, h);
|
||||
|
||||
@@ -705,9 +774,9 @@ public class FCardImageRenderer {
|
||||
int padding = TEXT_SIZE / 4;
|
||||
x += padding;
|
||||
w -= 2 * padding;
|
||||
if ((flagPTBox & 2) == 2)
|
||||
if ((textBoxFlags & 2) == 2)
|
||||
w -= PT_BOX_WIDTH;
|
||||
drawTextBoxText(g, text, x, y, w, h, flagPTBox);
|
||||
drawTextBoxText(g, text, x, y + yAdjust, w, h - yAdjust, textBoxFlags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -726,18 +795,22 @@ public class FCardImageRenderer {
|
||||
}
|
||||
}
|
||||
else if (state.isPlaneswalker()) {
|
||||
Color [] pwColor = { Color.BLACK };
|
||||
colors = pwColor;
|
||||
TEXT_COLOR = Color.WHITE;
|
||||
pieces.add(String.valueOf(state.getLoyalty()));
|
||||
}
|
||||
else if (state.getType().hasSubtype("Vehicle")) {
|
||||
pieces.add("[");
|
||||
Color [] vhColor = { new Color(128, 96, 64) };
|
||||
colors = vhColor;
|
||||
TEXT_COLOR = Color.WHITE;
|
||||
pieces.add(String.valueOf(state.getPower()));
|
||||
pieces.add("/");
|
||||
pieces.add(String.valueOf(state.getToughness()));
|
||||
pieces.add("]");
|
||||
}
|
||||
else { return; }
|
||||
|
||||
Font font = getShrinkFont(PT_FONT, PT_SIZE);
|
||||
Font font = getFontBySize(PT_FONT, PT_SIZE);
|
||||
FontMetrics metrics = g.getFontMetrics(font);
|
||||
int padding = PT_SIZE / 4;
|
||||
int totalPieceWidth = -padding;
|
||||
@@ -747,24 +820,21 @@ public class FCardImageRenderer {
|
||||
pieceWidths[i] = pieceWidth;
|
||||
totalPieceWidth += pieceWidth;
|
||||
}
|
||||
int boxHeight = metrics.getMaxAscent() + padding;
|
||||
x += w - PT_BOX_WIDTH;
|
||||
w = PT_BOX_WIDTH;
|
||||
|
||||
int boxWidth = Math.max(PT_BOX_WIDTH, totalPieceWidth + 2 * padding);
|
||||
x += w - boxWidth;
|
||||
y += h - boxHeight;
|
||||
w = boxWidth;
|
||||
h = boxHeight;
|
||||
int arcWidth = h / 3;
|
||||
fillRoundColorBackground(g, colors, x, y, w, h, arcWidth, h);
|
||||
g.setStroke(new BasicStroke(BOX_LINE_THICKNESS));
|
||||
g.setColor(state.isPlaneswalker() ? Color.WHITE : Color.BLACK);
|
||||
g.drawRoundRect(x, y, w, h, arcWidth, h);
|
||||
|
||||
fillColorBackground(g, colors, x, y, w, h);
|
||||
g.setStroke(new BasicStroke(BORDER_THICKNESS));
|
||||
g.setColor(Color.BLACK);
|
||||
g.drawRect(x, y, w, h);
|
||||
|
||||
x += (boxWidth - totalPieceWidth) / 2;
|
||||
x += (PT_BOX_WIDTH - totalPieceWidth) / 2;
|
||||
for (int i = 0; i < pieces.size(); i++) {
|
||||
drawVerticallyCenteredString(g, pieces.get(i), new Rectangle(x, y - 2, w, h), PT_FONT, PT_SIZE);
|
||||
x += pieceWidths[i];
|
||||
}
|
||||
TEXT_COLOR = Color.BLACK;
|
||||
}
|
||||
|
||||
private static abstract class Piece {
|
||||
@@ -986,8 +1056,8 @@ public class FCardImageRenderer {
|
||||
}
|
||||
|
||||
// Find font size that fit in the text box area
|
||||
Font txFont = getShrinkFont(TEXT_FONT, TEXT_SIZE);
|
||||
Font rmFont = getShrinkFont(REMINDER_FONT, REMINDER_SIZE);
|
||||
Font txFont = getFontBySize(TEXT_FONT, TEXT_SIZE);
|
||||
Font rmFont = getFontBySize(REMINDER_FONT, REMINDER_SIZE);
|
||||
FontMetrics txMetrics = g.getFontMetrics(txFont);
|
||||
FontMetrics rmMetrics = g.getFontMetrics(rmFont);
|
||||
int txFontSize = txFont.getSize(), rmFontSize = rmFont.getSize();
|
||||
@@ -1017,10 +1087,10 @@ public class FCardImageRenderer {
|
||||
break;
|
||||
//Shrink font and do again
|
||||
--txFontSize;
|
||||
txFont = getShrinkFont(TEXT_FONT, txFontSize);
|
||||
txFont = getFontBySize(TEXT_FONT, txFontSize);
|
||||
txMetrics = g.getFontMetrics(txFont);
|
||||
--rmFontSize;
|
||||
rmFont = getShrinkFont(REMINDER_FONT, rmFontSize);
|
||||
rmFont = getFontBySize(REMINDER_FONT, rmFontSize);
|
||||
rmMetrics = g.getFontMetrics(rmFont);
|
||||
} while (txFontSize >= 8 && rmFontSize >= 8);
|
||||
|
||||
@@ -1037,7 +1107,7 @@ public class FCardImageRenderer {
|
||||
y += pg.drawPieces(g, x + xoffset, y, w, lineSpacing + lineHeight, txFont, txMetrics, rmFont, rmMetrics);
|
||||
y += paraSpacing - lineSpacing;
|
||||
if (isLevelBox) {
|
||||
txFont = getShrinkFont(TEXT_FONT, txFontSize + 10);
|
||||
txFont = getFontBySize(TEXT_FONT, txFontSize + 10);
|
||||
txMetrics = g.getFontMetrics(txFont);
|
||||
y -= paraSpacing;
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@ ManaCost:2 W W
|
||||
Types:Creature Bird
|
||||
PT:3/3
|
||||
K:Flying
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ TrigEnergy | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, you get {E} (an energy counter).
|
||||
T:Mode$ ChangesZone | ValidCard$ Creature.Other+YouCtrl | Origin$ Any | Destination$ Battlefield | Execute$ TrigEnergy | TriggerZones$ Battlefield | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, you get {E} (an energy counter).
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.Self,Creature.YouCtrl | Origin$ Any | Destination$ Battlefield | Execute$ TrigEnergy | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, you get {E} (an energy counter).
|
||||
SVar:TrigEnergy:DB$ PutCounter | Defined$ You | CounterType$ ENERGY | CounterNum$ 1
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME attacks, you may pay {E}{E}. If you do, put a +1/+1 counter on it and tap up to one target creature defending player controls.
|
||||
SVar:TrigPutCounter:AB$ PutCounter | Cost$ PayEnergy<2> | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBTap
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Agent of Erebos
|
||||
ManaCost:3 B
|
||||
Types:Enchantment Creature Zombie
|
||||
PT:2/2
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, exile all cards from target player's graveyard.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Enchantment.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigExile | Secondary$ True | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, exile all cards from target player's graveyard.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.YouCtrl | Execute$ TrigExile | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, exile all cards from target player's graveyard.
|
||||
SVar:TrigExile:DB$ ChangeZoneAll | Origin$ Graveyard | Destination$ Exile | ValidTgts$ Player | TgtPrompt$ Select target player | ChangeType$ Card
|
||||
AI:RemoveDeck:Random
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/agent_of_erebos.jpg
|
||||
|
||||
@@ -3,8 +3,7 @@ ManaCost:2 B
|
||||
Types:Creature Orc Shaman
|
||||
PT:2/2
|
||||
K:Dash:3 B
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ TrigPump | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, that creature gets +2/+2.
|
||||
T:Mode$ ChangesZone | ValidCard$ Creature.Other+YouCtrl | Origin$ Any | Destination$ Battlefield | Execute$ TrigPump | TriggerZones$ Battlefield | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, that creature gets +2/+2.
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.Self,Creature.YouCtrl | Origin$ Any | Destination$ Battlefield | Execute$ TrigPump | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, that creature gets +2/+2.
|
||||
SVar:TrigPump:DB$ Pump | Defined$ TriggeredCard | NumAtt$ +2 | NumDef$ +2
|
||||
SVar:BuffedBy:Creature
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/ambuscade_shaman.jpg
|
||||
|
||||
@@ -3,8 +3,7 @@ ManaCost:3 W W
|
||||
Types:Creature Archon
|
||||
PT:3/4
|
||||
K:Flying
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | OptionalDecider$ You | Execute$ TrigGainLife | TriggerDescription$ Whenever CARDNAME or another creature with flying enters the battlefield under your control, you may gain life equal to that creature's power.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Other+YouCtrl+withFlying | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigGainLife | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another creature with flying enters the battlefield under your control, you may gain life equal to that creature's power.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Creature.Other+YouCtrl+withFlying | OptionalDecider$ You | Execute$ TrigGainLife | TriggerDescription$ Whenever CARDNAME or another creature with flying enters the battlefield under your control, you may gain life equal to that creature's power.
|
||||
SVar:TrigGainLife:DB$GainLife | Defined$ You | LifeAmount$ X
|
||||
SVar:X:TriggeredCard$CardPower
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/archon_of_redemption.jpg
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Ayara, First of Locthwain
|
||||
ManaCost:B B B
|
||||
Types:Legendary Creature Elf Noble
|
||||
PT:2/3
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDrain | TriggerDescription$ Whenever CARDNAME or another black creature enters the battlefield under your control, each opponent loses 1 life and you gain 1 life.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Black+Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDrain | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another black creature enters the battlefield under your control, each opponent loses 1 life and you gain 1 life.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Creature.Black+Other+YouCtrl | Execute$ TrigDrain | TriggerDescription$ Whenever CARDNAME or another black creature enters the battlefield under your control, each opponent loses 1 life and you gain 1 life.
|
||||
SVar:TrigDrain:DB$ LoseLife | Defined$ Player.Opponent | LifeAmount$ 1 | SubAbility$ DBGainLife
|
||||
SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 1
|
||||
A:AB$ Draw | Cost$ T Sac<1/Creature.Other+Black/another black creature> | NumCards$ 1 | SpellDescription$ Draw a card.
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Bala Ged Thief
|
||||
ManaCost:3 B
|
||||
Types:Creature Human Rogue Ally
|
||||
PT:2/2
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ DBDiscard | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, target player reveals a number of cards from their hand equal to the number of Allies you control. You choose one of them. That player discards that card.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Ally.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ DBDiscard | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, target player reveals a number of cards from their hand equal to the number of Allies you control. You choose one of them. That player discards that card.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Ally.Other+YouCtrl | Execute$ DBDiscard | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, target player reveals a number of cards from their hand equal to the number of Allies you control. You choose one of them. That player discards that card.
|
||||
SVar:DBDiscard:DB$ Discard | ValidTgts$ Player | NumCards$ 1 | RevealNumber$ X | Mode$ RevealYouChoose | DiscardValid$ Card
|
||||
SVar:X:Count$TypeYouCtrl.Ally
|
||||
SVar:BuffedBy:Ally
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Blood Artist
|
||||
ManaCost:1 B
|
||||
Types:Creature Vampire
|
||||
PT:0/1
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.Other | TriggerZones$ Battlefield | Execute$ TrigLoseLife | TriggerDescription$ Whenever CARDNAME or another creature dies, target player loses 1 life and you gain 1 life.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | TriggerController$ TriggeredCardController | Execute$ TrigLoseLife | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another creature dies, target player loses 1 life and you gain 1 life.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self,Creature.Other | TriggerZones$ Battlefield | Execute$ TrigLoseLife | TriggerDescription$ Whenever CARDNAME or another creature dies, target player loses 1 life and you gain 1 life.
|
||||
SVar:TrigLoseLife:DB$ LoseLife | ValidTgts$ Player | TgtPrompt$ Choose a player to lose life | LifeAmount$ 1 | SubAbility$ DBGainLife
|
||||
SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 1
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/blood_artist.jpg
|
||||
|
||||
@@ -3,8 +3,7 @@ ManaCost:1 B
|
||||
Types:Creature Human Warrior Ally
|
||||
PT:1/1
|
||||
K:CARDNAME can't block.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Ally.Other+YouCtrl | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigPutCounter | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Ally.Other+YouCtrl | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
SVar:TrigPutCounter:DB$PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
|
||||
SVar:BuffedBy:Ally
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/bojuka_brigand.jpg
|
||||
|
||||
@@ -2,5 +2,5 @@ Name:Bond of Flourishing
|
||||
ManaCost:1 G
|
||||
Types:Sorcery
|
||||
A:SP$ Dig | Cost$ 1 G | DigNum$ 3 | ChangeNum$ 1 | Optional$ True | ChangeValid$ Permanent | DestinationZone$ Hand | DestinationZone2$ Library | LibraryPosition$ -1 | RestRandomOrder$ True | SubAbility$ GainLife | SpellDescription$ Look at the top three cards of your library. You may reveal a permanent card from among them and put it into your hand. Put the rest on the bottom of your library in any order. You gain 3 life.
|
||||
SVar:GainLife:DB$GainLife | LifeAmount$ 3
|
||||
SVar:GainLife:DB$ GainLife | LifeAmount$ 3
|
||||
Oracle:Look at the top three cards of your library. You may reveal a permanent card from among them and put it into your hand. Put the rest on the bottom of your library in any order. You gain 3 life.
|
||||
|
||||
@@ -2,5 +2,5 @@ Name:Bond of Passion
|
||||
ManaCost:4 R R
|
||||
Types:Sorcery
|
||||
A:SP$ GainControl | Cost$ 4 R R | ValidTgts$ Creature | TgtPrompt$ Select target creature. | LoseControl$ EOT | Untap$ True | AddKWs$ Haste | SubAbility$ DBDamage | SpellDescription$ Gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn. CARDNAME deals 2 damage to any target.
|
||||
SVar:DBDamage:DB$DealDamage | ValidTgts$ Creature,Player,Planeswalker | NumDmg$ 2 | TargetUnique$ True | TgtPrompt$ Select any target.
|
||||
SVar:DBDamage:DB$ DealDamage | ValidTgts$ Creature,Player,Planeswalker | NumDmg$ 2 | TargetUnique$ True | TgtPrompt$ Select any target.
|
||||
Oracle:Gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn. Bond of Passion deals 2 damage to any other target.
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Coercive Recruiter
|
||||
ManaCost:4 R
|
||||
Types:Creature Orc Pirate
|
||||
PT:4/3
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ TrigGainControl | TriggerDescription$ Whenever CARDNAME or another Pirate enters the battlefield under your control, gain control of target creature until end of turn. Untap that creature. Until end of turn, it gains haste and becomes a Pirate in addition to its other types.
|
||||
T:Mode$ ChangesZone | ValidCard$ Pirate.Other+YouCtrl | Origin$ Any | Destination$ Battlefield | Execute$ TrigGainControl | Secondary$ True | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME or another Pirate enters the battlefield under your control, gain control of target creature until end of turn. Untap that creature. Until end of turn, it gains haste and becomes a Pirate in addition to its other types.
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.Self,Pirate.Other+YouCtrl | Origin$ Any | Destination$ Battlefield | Execute$ TrigGainControl | TriggerDescription$ Whenever CARDNAME or another Pirate enters the battlefield under your control, gain control of target creature until end of turn. Untap that creature. Until end of turn, it gains haste and becomes a Pirate in addition to its other types.
|
||||
SVar:TrigGainControl:DB$ GainControl | ValidTgts$ Creature | TgtPrompt$ Select target creature | LoseControl$ EOT | Untap$ True | AddKWs$ Haste | SubAbility$ DBAnimate
|
||||
SVar:DBAnimate:DB$ Animate | Defined$ Targeted | Types$ Pirate | UntilEndOfTurn$ True
|
||||
DeckNeeds:Type$Pirate
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
Name:Daxos's Torment
|
||||
ManaCost:3 B
|
||||
Types:Enchantment
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigAnimate | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, CARDNAME becomes a 5/5 Demon creature with flying and haste in addition to its other types until end of turn.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Enchantment.Other+YouCtrl | TriggerZones$ Battlefield | Secondary$ True | Execute$ TrigAnimate | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, CARDNAME becomes a 5/5 Demon creature with flying and haste in addition to its other types until end of turn.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.Other+YouCtrl | Execute$ TrigAnimate | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, CARDNAME becomes a 5/5 Demon creature with flying and haste in addition to its other types until end of turn.
|
||||
SVar:TrigAnimate:DB$ Animate | Defined$ Self | Power$ 5 | Toughness$ 5 | Types$ Creature,Demon | Keywords$ Flying & Haste
|
||||
SVar:PlayMain1:ALWAYS
|
||||
SVar:BuffedBy:Enchantment
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Doomwake Giant
|
||||
ManaCost:4 B
|
||||
Types:Enchantment Creature Giant
|
||||
PT:4/6
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMassacre | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, creatures your opponents control get -1/-1 until end of turn.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Enchantment.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigMassacre | Secondary$ True | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, creatures your opponents control get -1/-1 until end of turn.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.Other+YouCtrl | Execute$ TrigMassacre | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, creatures your opponents control get -1/-1 until end of turn.
|
||||
SVar:TrigMassacre:DB$ PumpAll | NumAtt$ -1 | NumDef$ -1 | ValidCards$ Creature.OppCtrl | IsCurse$ True
|
||||
SVar:PlayMain1:TRUE
|
||||
SVar:BuffedBy:Enchantment
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Dreadbringer Lampads
|
||||
ManaCost:4 B
|
||||
Types:Enchantment Creature Nymph
|
||||
PT:4/2
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPump | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, target creature gains intimidate until end of turn.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Enchantment.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPump | Secondary$ True | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, target creature gains intimidate until end of turn.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.Other+YouCtrl | Execute$ TrigPump | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, target creature gains intimidate until end of turn.
|
||||
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | KW$ Intimidate
|
||||
SVar:BuffedBy:Enchantment
|
||||
SVar:PlayMain1:TRUE
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Eidolon of Blossoms
|
||||
ManaCost:2 G G
|
||||
Types:Enchantment Creature Spirit
|
||||
PT:2/2
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDraw | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, draw a card.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Enchantment.Other+YouCtrl | TriggerZones$ Battlefield | Secondary$ True | Execute$ TrigDraw | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, draw a card.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.Other+YouCtrl | Execute$ TrigDraw | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, draw a card.
|
||||
SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1
|
||||
SVar:BuffedBy:Enchantment
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/eidolon_of_blossoms.jpg
|
||||
|
||||
@@ -3,8 +3,7 @@ ManaCost:no cost
|
||||
Types:Land
|
||||
K:CARDNAME enters the battlefield tapped.
|
||||
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | CheckSVar$ X | SVarCompare$ GE7 | Execute$ TrigToken | TriggerDescription$ Whenever CARDNAME or another land enters the battlefield under your control, if you control seven or more lands with different names, create a 2/2 black Zombie creature token.
|
||||
T:Mode$ ChangesZone | TriggerZones$ Battlefield | CheckSVar$ X | SVarCompare$ GE7 | Origin$ Any | Destination$ Battlefield | ValidCard$ Land.Other+YouCtrl | Execute$ TrigToken | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another land enters the battlefield under your control, if you control seven or more lands with different names, create a 2/2 black Zombie creature token.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Land.Other+YouCtrl | CheckSVar$ X | SVarCompare$ GE7 | Execute$ TrigToken | TriggerDescription$ Whenever CARDNAME or another land enters the battlefield under your control, if you control seven or more lands with different names, create a 2/2 black Zombie creature token.
|
||||
SVar:TrigToken:DB$ Token | TokenScript$ b_2_2_zombie | TokenOwner$ You | TokenAmount$ 1 | LegacyImage$ b 2 2 zombie m20
|
||||
SVar:X:Count$DifferentCardNames_Land.YouCtrl+inZoneBattlefield
|
||||
DeckHas:Ability$Token
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Forgeborn Oreads
|
||||
ManaCost:2 R R
|
||||
Types:Enchantment Creature Nymph
|
||||
PT:4/2
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDamage | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, CARDNAME deals 1 damage to any target.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Enchantment.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDamage | Secondary$ True | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, CARDNAME deals 1 damage to any target.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.Other+YouCtrl | Execute$ TrigDamage | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, CARDNAME deals 1 damage to any target.
|
||||
SVar:TrigDamage:DB$ DealDamage | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ 1
|
||||
SVar:PlayMain1:TRUE
|
||||
SVar:BuffedBy:Enchantment
|
||||
|
||||
@@ -3,8 +3,7 @@ ManaCost:1 W B
|
||||
Types:Legendary Creature Human Soldier
|
||||
PT:3/3
|
||||
S:Mode$ Continuous | Affected$ Human.Other+YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Other Humans you control get +1/+1.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ Whenever CARDNAME or another Human enters the battlefield under your control, exile target card from an opponent's graveyard.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Other+Human+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigExile | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Human enters the battlefield under your control, exile target card from an opponent's graveyard.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Creature.Other+Human+YouCtrl | Execute$ TrigExile | TriggerDescription$ Whenever CARDNAME or another Human enters the battlefield under your control, exile target card from an opponent's graveyard.
|
||||
SVar:TrigExile:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | TgtPrompt$ Choose target card in an opponent's graveyard | ValidTgts$ Card.OppOwn
|
||||
A:AB$ Destroy | Cost$ 2 Sac<2/Human> | ValidTgts$ Creature.powerGE4 | TgtPrompt$ Select target creature with power 4 or greater | SpellDescription$ Destroy target creature with power 4 or greater.
|
||||
DeckHints:Type$Human
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Goblin Assassin
|
||||
ManaCost:3 R R
|
||||
Types:Creature Goblin Assassin
|
||||
PT:2/2
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ RepeatFlips | TriggerDescription$ Whenever CARDNAME or another Goblin enters the battlefield, each player flips a coin. Each player whose coin comes up tails sacrifices a creature.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Goblin.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ RepeatFlips | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Goblin enters the battlefield, each player flips a coin. Each player whose coin comes up tails sacrifices a creature.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Goblin.Other+YouCtrl | Execute$ RepeatFlips | TriggerDescription$ Whenever CARDNAME or another Goblin enters the battlefield, each player flips a coin. Each player whose coin comes up tails sacrifices a creature.
|
||||
SVar:RepeatFlips:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ AssassinsFlip | SubAbility$ Assassination
|
||||
SVar:AssassinsFlip:DB$ FlipACoin | Flipper$ Remembered | NoCall$ True | RememberResult$ True
|
||||
SVar:Assassination:DB$ Sacrifice | Defined$ FlippedTails | SacValid$ Creature | Amount$ 1 | SubAbility$ ResetFlips
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Goldenhide Ox
|
||||
ManaCost:5 G
|
||||
Types:Enchantment Creature Ox
|
||||
PT:5/4
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPump | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, target creature must be blocked this turn if able.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Enchantment.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPump | Secondary$ True | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, target creature must be blocked this turn if able.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.Other+YouCtrl | Execute$ TrigPump | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, target creature must be blocked this turn if able.
|
||||
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | KW$ HIDDEN CARDNAME must be blocked if able. | AILogic$ Pump
|
||||
SVar:PlayMain1:TRUE
|
||||
SVar:BuffedBy:Enchantment
|
||||
|
||||
@@ -3,8 +3,7 @@ ManaCost:3 G
|
||||
Types:Creature Human Warrior Ally
|
||||
PT:2/2
|
||||
K:Trample
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Ally.Other+YouCtrl | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigPutCounter | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Ally.Other+YouCtrl | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
SVar:TrigPutCounter:DB$PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
|
||||
SVar:BuffedBy:Ally
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/graypelt_hunter.jpg
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Grim Guardian
|
||||
ManaCost:2 B
|
||||
Types:Enchantment Creature Zombie
|
||||
PT:1/4
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDrain | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, each opponent loses 1 life.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Enchantment.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDrain | Secondary$ True | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, each opponent loses 1 life.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.Other+YouCtrl | Execute$ TrigDrain | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, each opponent loses 1 life.
|
||||
SVar:TrigDrain:DB$ LoseLife | Defined$ Player.Opponent | LifeAmount$ 1
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/grim_guardian.jpg
|
||||
Oracle:Constellation — Whenever Grim Guardian or another enchantment enters the battlefield under your control, each opponent loses 1 life.
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Grovetender Druids
|
||||
ManaCost:2 G W
|
||||
Types:Creature Elf Druid Ally
|
||||
PT:3/3
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ Rally — Whenever CARDNAME or another Ally enters the battlefield under your control, you may pay {1}. If you do, create a 1/1 green Plant creature token.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Ally.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigToken | Secondary$ True | TriggerDescription$ Rally — Whenever CARDNAME or another Ally enters the battlefield under your control, you may pay {1}. If you do, create a 1/1 green Plant creature token.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Ally.Other+YouCtrl | Execute$ TrigToken | TriggerDescription$ Rally — Whenever CARDNAME or another Ally enters the battlefield under your control, you may pay {1}. If you do, create a 1/1 green Plant creature token.
|
||||
SVar:TrigToken:AB$ Token | Cost$ 1 | TokenAmount$ 1 | TokenScript$ g_1_1_plant | LegacyImage$ g 1 1 plant bfz | TokenOwner$ You
|
||||
DeckHints:Type$Ally
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/grovetender_druids.jpg
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Gruul Ragebeast
|
||||
ManaCost:5 R G
|
||||
Types:Creature Beast
|
||||
PT:6/6
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigFight | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, that creature fights target creature an opponent controls.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigFight | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, that creature fights target creature an opponent controls.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Creature.Other+YouCtrl | Execute$ TrigFight | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, that creature fights target creature an opponent controls.
|
||||
SVar:TrigFight:DB$ Fight | Defined$ TriggeredCardLKICopy | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls.
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/gruul_ragebeast.jpg
|
||||
Oracle:Whenever Gruul Ragebeast or another creature enters the battlefield under your control, that creature fights target creature an opponent controls.
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Hada Freeblade
|
||||
ManaCost:W
|
||||
Types:Creature Human Soldier Ally
|
||||
PT:0/1
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Ally.Other+YouCtrl | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigPutCounter | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Ally.Other+YouCtrl | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
SVar:TrigPutCounter:DB$PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
|
||||
SVar:BuffedBy:Ally
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/hada_freeblade.jpg
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Halimar Excavator
|
||||
ManaCost:1 U
|
||||
Types:Creature Human Wizard Ally
|
||||
PT:1/3
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMill | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, target player mills X cards, where X is the number of Allies you control.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Ally.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigMill | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, target player mills X cards, where X is the number of Allies you control.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Ally.Other+YouCtrl | Execute$ TrigMill | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, target player mills X cards, where X is the number of Allies you control.
|
||||
SVar:TrigMill:DB$ Mill | ValidTgts$ Player | NumCards$ X | TgtPrompt$ Select a target player. | SpellDescription$ Target player mills X cards, where X is the number of Allies you control.
|
||||
SVar:X:Count$Valid Ally.YouCtrl
|
||||
SVar:BuffedBy:Ally
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
Name:Hammer of Nazahn
|
||||
ManaCost:4
|
||||
Types:Legendary Artifact Equipment
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigAttach | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME or another Equipment enters the battlefield under your control, you may attach that Equipment to target creature you control.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Equipment+Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigAttach | OptionalDecider$ You | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Equipment enters the battlefield under your control, that Equipment to target creature you control.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Card.Equipment+Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigAttach | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME or another Equipment enters the battlefield under your control, you may attach that Equipment to target creature you control.
|
||||
SVar:TrigAttach:DB$ Attach | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Target creature you control | Object$ TriggeredCard
|
||||
S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 2 | AddKeyword$ Indestructible | Description$ Equipped creature gets +2/+0 and has indestructible.
|
||||
K:Equip:4
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Harvestguard Alseids
|
||||
ManaCost:2 W
|
||||
Types:Enchantment Creature Nymph
|
||||
PT:2/3
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPump | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, prevent all damage that would be dealt to target creature this turn.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Enchantment.Other+YouCtrl | TriggerZones$ Battlefield | Secondary$ True | Execute$ TrigPump | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, prevent all damage that would be dealt to target creature this turn.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.Other+YouCtrl | Execute$ TrigPump | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, prevent all damage that would be dealt to target creature this turn.
|
||||
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | KW$ Prevent all damage that would be dealt to CARDNAME.
|
||||
SVar:PlayMain1:TRUE
|
||||
SVar:BuffedBy:Enchantment
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Humbler of Mortals
|
||||
ManaCost:4 G G
|
||||
Types:Enchantment Creature Elemental
|
||||
PT:5/5
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPump | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, creatures you control gain trample until end of turn.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Enchantment.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPump | Secondary$ True | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, creatures you control gain trample until end of turn.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.Other+YouCtrl | Execute$ TrigPump | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, creatures you control gain trample until end of turn.
|
||||
SVar:TrigPump:DB$ PumpAll | ValidCards$ Creature.YouCtrl | KW$ Trample | SpellDescription$ Creatures you control gain trample until end of turn.
|
||||
SVar:PlayMain1:TRUE
|
||||
SVar:BuffedBy:Enchantment
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Joraga Bard
|
||||
ManaCost:3 G
|
||||
Types:Creature Elf Rogue Bard Ally
|
||||
PT:1/4
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | OptionalDecider$ You | Execute$ TrigPump | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may have Ally creatures you control gain vigilance until end of turn.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Ally.Other+YouCtrl | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigPump | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may have Ally creatures you control gain vigilance until end of turn.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Ally.Other+YouCtrl | OptionalDecider$ You | Execute$ TrigPump | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may have Ally creatures you control gain vigilance until end of turn.
|
||||
SVar:TrigPump:DB$ PumpAll | ValidCards$ Ally.YouCtrl | KW$ Vigilance
|
||||
SVar:PlayMain1:TRUE
|
||||
SVar:BuffedBy:Ally
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Kalastria Healer
|
||||
ManaCost:1 B
|
||||
Types:Creature Vampire Cleric Ally
|
||||
PT:1/2
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDrain | TriggerDescription$ Rally — Whenever CARDNAME or another Ally enters the battlefield under your control, each opponent loses 1 life and you gain 1 life.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Ally.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDrain | Secondary$ True | TriggerDescription$ Rally — Whenever CARDNAME or another Ally enters the battlefield under your control, each opponent loses 1 life and you gain 1 life.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Ally.Other+YouCtrl | Execute$ TrigDrain | TriggerDescription$ Rally — Whenever CARDNAME or another Ally enters the battlefield under your control, each opponent loses 1 life and you gain 1 life.
|
||||
SVar:TrigDrain:DB$ LoseLife | Defined$ Player.Opponent | LifeAmount$ 1 | SubAbility$ DBGainLife
|
||||
SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 1
|
||||
SVar:PlayMain1:TRUE
|
||||
|
||||
@@ -3,8 +3,7 @@ ManaCost:4 U U
|
||||
Types:Creature Fish
|
||||
PT:3/3
|
||||
K:Flying
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigTap | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, tap target creature an opponent controls.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.YouCtrl+Other | TriggerZones$ Battlefield | Execute$ TrigTap | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, tap target creature an opponent controls.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Creature.YouCtrl+Other | Execute$ TrigTap | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, tap target creature an opponent controls.
|
||||
SVar:TrigTap:DB$ Tap | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Choose target creature an opponent controls.
|
||||
SVar:BuffedBy:Creature
|
||||
SVar:PlayMain1:TRUE
|
||||
|
||||
@@ -4,8 +4,7 @@ Types:Creature Human Soldier Ally
|
||||
PT:1/1
|
||||
K:First Strike
|
||||
K:Vigilance
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Ally.Other+YouCtrl | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigPutCounter | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Ally.Other+YouCtrl | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
SVar:TrigPutCounter:DB$PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
|
||||
SVar:BuffedBy:Ally
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/kazandu_blademaster.jpg
|
||||
|
||||
@@ -2,9 +2,8 @@ Name:Kazuul Warlord
|
||||
ManaCost:4 R
|
||||
Types:Creature Minotaur Warrior Ally
|
||||
PT:3/3
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on each Ally creature you control.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Ally.Other+YouCtrl | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigPutCounter | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on each Ally creature you control.
|
||||
SVar:TrigPutCounter:DB$PutCounterAll | ValidCards$ Ally.YouCtrl | CounterType$ P1P1 | CounterNum$ 1
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Ally.Other+YouCtrl | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on each Ally creature you control.
|
||||
SVar:TrigPutCounter:DB$ PutCounterAll | ValidCards$ Ally.YouCtrl | CounterType$ P1P1 | CounterNum$ 1
|
||||
SVar:PlayMain1:TRUE
|
||||
SVar:BuffedBy:Ally
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/kazuul_warlord.jpg
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Kor Celebrant
|
||||
ManaCost:2 W
|
||||
Types:Creature Kor Cleric
|
||||
PT:1/4
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ TrigGainLife | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, you gain 1 life.
|
||||
T:Mode$ ChangesZone | ValidCard$ Creature.Other+YouCtrl | Origin$ Any | Destination$ Battlefield | Execute$ TrigGainLife | TriggerZones$ Battlefield | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, you gain 1 life.
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.Self,Creature.Other+YouCtrl | Origin$ Any | Destination$ Battlefield | Execute$ TrigGainLife | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, you gain 1 life.
|
||||
SVar:TrigGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 1
|
||||
DeckHas:Ability$LifeGain
|
||||
Oracle:Whenever Kor Celebrant or another creature enters the battlefield under your control, you gain 1 life.
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Kor Entanglers
|
||||
ManaCost:4 W
|
||||
Types:Creature Kor Soldier Ally
|
||||
PT:3/4
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigTap | TriggerDescription$ Rally — Whenever CARDNAME or another Ally enters the battlefield under your control, tap target creature an opponent controls.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Ally.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigTap | Secondary$ True | TriggerDescription$ Rally — Whenever CARDNAME or another Ally enters the battlefield under your control, tap target creature an opponent controls.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Ally.Other+YouCtrl | Execute$ TrigTap | TriggerDescription$ Rally — Whenever CARDNAME or another Ally enters the battlefield under your control, tap target creature an opponent controls.
|
||||
SVar:TrigTap:DB$ Tap | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Choose target creature an opponent controls.
|
||||
SVar:PlayMain1:TRUE
|
||||
SVar:BuffedBy:Ally
|
||||
|
||||
@@ -3,8 +3,7 @@ ManaCost:2 W
|
||||
Types:Creature Kor Soldier Ally
|
||||
PT:0/3
|
||||
K:Defender
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Ally.Other+YouCtrl | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigPutCounter | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Ally.Other+YouCtr | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
SVar:TrigPutCounter:DB$PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
|
||||
SVar:BuffedBy:Ally
|
||||
AI:RemoveDeck:Random
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Mardu Woe-Reaper
|
||||
ManaCost:W
|
||||
Types:Creature Human Warrior
|
||||
PT:2/1
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | OptionalDecider$ You | Execute$ TrigExile| TriggerDescription$ Whenever CARDNAME or another Warrior enters the battlefield under your control, you may exile target creature card from a graveyard. If you do, you gain 1 life.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Warrior.Other+YouCtrl | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigExile | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Warrior enters the battlefield under your control, you may exile target creature card from a graveyard. If you do, you gain 1 life.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Warrior.Other+YouCtrl | OptionalDecider$ You | Execute$ TrigExile | TriggerDescription$ Whenever CARDNAME or another Warrior enters the battlefield under your control, you may exile target creature card from a graveyard. If you do, you gain 1 life.
|
||||
SVar:TrigExile:DB$ ChangeZone | ValidTgts$ Creature | TgtPrompt$ Select target creature card | Origin$ Graveyard | Destination$ Exile | RememberChanged$ True | SubAbility$ DBGainLife
|
||||
SVar:DBGainLife:DB$ GainLife | LifeAmount$ 1 | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ1 | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
Name:Marit Lage's Slumber
|
||||
ManaCost:1 U
|
||||
Types:Legendary Snow Enchantment
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Permanent.Snow+Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigScry | TriggerDescription$ Whenever CARDNAME or another snow permanent enters the battlefield under your control, scry 1.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Secondary$ True | Execute$ TrigScry | TriggerDescription$ Whenever CARDNAME or another snow permanent enters the battlefield under your control, scry 1.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Permanent.Snow+Other+YouCtrl | Execute$ TrigScry | TriggerDescription$ Whenever CARDNAME or another snow permanent enters the battlefield under your control, scry 1.
|
||||
SVar:TrigScry:DB$ Scry | ScryNum$ 1 | SpellDescription$ Scry 1.
|
||||
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | IsPresent$ Permanent.Snow+YouCtrl | PresentCompare$ GE10 | Execute$ TrigSac | TriggerDescription$ At the beginning of your upkeep, if you control ten or more snow permanents, sacrifice CARDNAME. If you do, create Marit Lage, a legendary 20/20 black Avatar creature token with flying and indestructible.
|
||||
SVar:TrigSac:DB$ Sacrifice | RememberSacrificed$ True | SubAbility$ DBToken
|
||||
|
||||
@@ -3,8 +3,7 @@ ManaCost:2 R W
|
||||
Types:Legendary Creature Kor Ally
|
||||
PT:3/4
|
||||
K:Haste
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDig | OptionalDecider$ You | TriggerDescription$ Rally — Whenever CARDNAME or another Ally enters the battlefield under your control, you may look at the top four cards of your library. If you do, reveal any number of Ally cards from among them, then put those cards on top of your library in any order and the rest on the bottom in any order.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Ally.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDig | Secondary$ True | OptionalDecider$ You | TriggerDescription$ Rally — Whenever CARDNAME or another Ally enters the battlefield under your control, you may look at the top four cards of your library. If you do, reveal any number of Ally cards from among them, then put those cards on top of your library in any order and the rest on the bottom in any order.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Ally.Other+YouCtrl | Execute$ TrigDig | OptionalDecider$ You | TriggerDescription$ Rally — Whenever CARDNAME or another Ally enters the battlefield under your control, you may look at the top four cards of your library. If you do, reveal any number of Ally cards from among them, then put those cards on top of your library in any order and the rest on the bottom in any order.
|
||||
SVar:TrigDig:DB$ Dig | DigNum$ 4 | AnyNumber$ True | ChangeValid$ Ally | DestinationZone$ Library | LibraryPosition$ 0
|
||||
DeckHints:Type$Ally
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/munda_ambush_leader.jpg
|
||||
|
||||
@@ -4,8 +4,7 @@ Types:Creature Spirit
|
||||
PT:2/1
|
||||
K:Flash
|
||||
K:Flying
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigTap | TriggerDescription$ Whenever Nebelgast Herald or another Spirit enters the battlefield under your control, tap target creature an opponent controls.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Spirit+YouCtrl+Other | TriggerZones$ Battlefield | Execute$ TrigTap | Secondary$ True | TriggerDescription$ Whenever another white creature enters the battlefield under your control, tap target creature an opponent controls.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Spirit.YouCtrl+Other | Execute$ TrigTap | TriggerDescription$ Whenever CARDNAME or another Spirit enters the battlefield under your control, tap target creature an opponent controls.
|
||||
SVar:TrigTap:DB$ Tap | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Choose target creature an opponent controls.
|
||||
SVar:BuffedBy:Spirit
|
||||
DeckHints:Type$Spirit
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Nimana Sell-Sword
|
||||
ManaCost:3 B
|
||||
Types:Creature Human Warrior Ally
|
||||
PT:2/2
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Ally.Other+YouCtrl | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigPutCounter | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Ally.Other+YouCtrl | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
SVar:TrigPutCounter:DB$PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
|
||||
SVar:BuffedBy:Ally
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/nimana_sell_sword.jpg
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Noxious Ghoul
|
||||
ManaCost:3 B B
|
||||
Types:Creature Zombie
|
||||
PT:3/3
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPumpAll | TriggerDescription$ Whenever CARDNAME or another Zombie enters the battlefield, all non-Zombie creatures get -1/-1 until end of turn.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Zombie.Other | Execute$ TrigPumpAll | TriggerZones$ Battlefield | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Zombie enters the battlefield, all non-Zombie creatures get -1/-1 until end of turn.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Zombie.Other | Execute$ TrigPumpAll | TriggerDescription$ Whenever CARDNAME or another Zombie enters the battlefield, all non-Zombie creatures get -1/-1 until end of turn.
|
||||
SVar:TrigPumpAll:DB$ PumpAll | ValidCards$ Creature.nonZombie | NumAtt$ -1 | NumDef$ -1 | IsCurse$ True
|
||||
SVar:PlayMain1:TRUE
|
||||
Oracle:Whenever Noxious Ghoul or another Zombie enters the battlefield, all non-Zombie creatures get -1/-1 until end of turn.
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Nylea's Colossus
|
||||
ManaCost:6 G
|
||||
Types:Enchantment Creature Giant
|
||||
PT:6/6
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPump | TriggerDescription$ Constellation Whenever CARDNAME or another enchantment enters the battlefield under your control, double target creature's power and toughness until end of turn.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Enchantment.Other+YouCtrl | TriggerZones$ Battlefield | Secondary$ True | Execute$ TrigPump | TriggerDescription$ Constellation Whenever CARDNAME or another enchantment enters the battlefield under your control, double target creature's power and toughness until end of turn.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.Other+YouCtrl | Execute$ TrigPump | TriggerDescription$ Constellation Whenever CARDNAME or another enchantment enters the battlefield under your control, double target creature's power and toughness until end of turn.
|
||||
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ +X | NumDef$ +Y | RememberTargets$ True | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:X:Remembered$CardPower
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Oakheart Dryads
|
||||
ManaCost:2 G
|
||||
Types:Enchantment Creature Nymph Dryad
|
||||
PT:2/3
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPump | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, target creature gets +1/+1 until end of turn.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Enchantment.Other+YouCtrl | TriggerZones$ Battlefield | Secondary$ True | Execute$ TrigPump | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, target creature gets +1/+1 until end of turn.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.Other+YouCtrl | Execute$ TrigPump | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, target creature gets +1/+1 until end of turn.
|
||||
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature | NumAtt$ +1 | NumDef$ +1
|
||||
SVar:BuffedBy:Enchantment
|
||||
SVar:PlayMain1:TRUE
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
Name:Oath of the Ancient Wood
|
||||
ManaCost:2 G
|
||||
Types:Enchantment
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Enchantment.Other+YouCtrl | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another enchantment enters the battlefield under your control, you may put a +1/+1 counter on target creature.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPutCounter | Secondary$ True | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME or another enchantment enters the battlefield under your control, you may put a +1/+1 counter on target creature.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.Other+YouCtrl | Execute$ TrigPutCounter | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME or another enchantment enters the battlefield under your control, you may put a +1/+1 counter on target creature.
|
||||
SVar:TrigPutCounter:DB$ PutCounter | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ P1P1 | CounterNum$ 1
|
||||
AI:RemoveDeck:Random
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/oath_of_the_ancient_wood.jpg
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Oran-Rief Survivalist
|
||||
ManaCost:1 G
|
||||
Types:Creature Human Warrior Ally
|
||||
PT:1/1
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Ally.Other+YouCtrl | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigPutCounter | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Ally.Other+YouCtrl | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another Ally enters the battlefield under your control, you may put a +1/+1 counter on CARDNAME.
|
||||
SVar:TrigPutCounter:DB$PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
|
||||
SVar:BuffedBy:Ally
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/oran_rief_survivalist.jpg
|
||||
|
||||
@@ -3,8 +3,7 @@ ManaCost:4 G
|
||||
Types:Creature Cat Warrior
|
||||
PT:3/5
|
||||
K:Reach
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDestroy | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME or another Cat enters the battlefield under your control, you may destroy target artifact or enchantment.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Cat.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDestroy | Secondary$ True | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME or another Cat enters the battlefield under your control, you may destroy target artifact or enchantment.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Cat.Other+YouCtrl | Execute$ TrigDestroy | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME or another Cat enters the battlefield under your control, you may destroy target artifact or enchantment.
|
||||
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact,Enchantment | TgtPrompt$ Select target artifact or enchantment
|
||||
DeckHints:Type$Cat
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/qasali_slingers.jpg
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Risen Reef
|
||||
ManaCost:1 G U
|
||||
Types:Creature Elemental
|
||||
PT:1/1
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPeek | TriggerDescription$ Whenever CARDNAME or another Elemental enters the battlefield under your control, look at the top card of your library. If it's a land card, you may put it onto the battlefield tapped. If you don't put the card onto the battlefield, put it into your hand.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Elemental.Other+YouCtrl | TriggerZones$ Battlefield | Secondary$ True | Execute$ TrigPeek | TriggerDescription$ Whenever CARDNAME or another Elemental enters the battlefield under your control, look at the top card of your library. If it's a land card, you may put it onto the battlefield tapped. If you don't put the card onto the battlefield, put it into your hand.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Elemental.Other+YouCtrl | Execute$ TrigPeek | TriggerDescription$ Whenever CARDNAME or another Elemental enters the battlefield under your control, look at the top card of your library. If it's a land card, you may put it onto the battlefield tapped. If you don't put the card onto the battlefield, put it into your hand.
|
||||
SVar:TrigPeek:DB$ PeekAndReveal | PeekAmount$ 1 | NoReveal$ True | RememberPeeked$ True | SubAbility$ DBChangeZone
|
||||
SVar:DBChangeZone:DB$ ChangeZone | Optional$ True | ForgetChanged$ True | Origin$ Library | Destination$ Battlefield | Defined$ Remembered | ConditionDefined$ Remembered | ConditionPresent$ Land | ConditionCompare$ GE1 | Tapped$ True | SubAbility$ DBHand
|
||||
SVar:DBHand:DB$ ChangeZone | Origin$ Library | Destination$ Hand | Defined$ Remembered | SubAbility$ DBCleanup
|
||||
|
||||
@@ -2,7 +2,6 @@ Name:Sage of the Falls
|
||||
ManaCost:4 U
|
||||
Types:Creature Merfolk Wizard
|
||||
PT:2/5
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigLoot | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME or another non-Human creature enters the battlefield under your control, you may draw a card. If you do, discard a card.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.nonHuman+Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigLoot | OptionalDecider$ You | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another non-Human creature enters the battlefield under your control, you may draw a card. If you do, discard a card.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Creature.nonHuman+Other+YouCtrl | Execute$ TrigLoot | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME or another non-Human creature enters the battlefield under your control, you may draw a card. If you do, discard a card.
|
||||
SVar:TrigLoot:AB$ Discard | Defined$ You | Mode$ TgtChoose | NumCards$ 1 | Cost$ Draw<1/You>
|
||||
Oracle:Whenever Sage of the Falls or another non-Human creature enters the battlefield under your control, you may draw a card. If you do, discard a card.
|
||||
|
||||
@@ -3,8 +3,7 @@ ManaCost:2 R R R
|
||||
Types:Creature Dragon
|
||||
PT:4/4
|
||||
K:Flying
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDamage | TriggerDescription$ Whenever CARDNAME or another Dragon enters the battlefield under your control, it deals X damage to any target, where X is the number of Dragons you control.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Dragon.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDamage | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Dragon enters the battlefield under your control, it deals X damage to any target, where X is the number of Dragons you control.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Dragon.Other+YouCtrl | Execute$ TrigDamage | TriggerDescription$ Whenever CARDNAME or another Dragon enters the battlefield under your control, it deals X damage to any target, where X is the number of Dragons you control.
|
||||
SVar:TrigDamage:DB$ DealDamage | ValidTgts$ Creature,Player,Planeswalker | NumDmg$ NumDragons | TgtPrompt$ Select any target | DamageSource$ TriggeredCard
|
||||
SVar:NumDragons:Count$Valid Dragon.YouCtrl
|
||||
A:AB$ Pump | Cost$ R | Defined$ Self | NumAtt$ +1 | SpellDescription$ CARDNAME gets +1/+0 until end of turn.
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
Name:Serum Tank
|
||||
ManaCost:3
|
||||
Types:Artifact
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another artifact enters the battlefield, put a charge counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | TriggerZones$ Battlefield | ValidCard$ Artifact.Other | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another artifact enters the battlefield, put a charge counter on CARDNAME. | Secondary$ True
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Artifact.Other | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another artifact enters the battlefield, put a charge counter on CARDNAME.
|
||||
A:AB$ Draw | Cost$ 3 T SubCounter<1/CHARGE> | NumCards$ 1 | SpellDescription$ Draw a card.
|
||||
SVar:TrigPutCounter:DB$PutCounter | Defined$ Self | CounterType$ CHARGE | CounterNum$ 1
|
||||
AI:RemoveDeck:Random
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Sethron, Hurloon General
|
||||
ManaCost:3 R R
|
||||
Types:Legendary Creature Minotaur Warrior
|
||||
PT:4/4
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | TriggerZones$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ Whenever CARDNAME or another nontoken Minotaur enters enters the battlefield under your control, create a 2/3 red Minotaur creature token.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | TriggerZones$ Battlefield | ValidCard$ Minotaur.nonToken+Other+YouCtrl | Execute$ TrigToken | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another nontoken Minotaur enters the battlefield under your control, create a 2/3 red Minotaur creature token.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | TriggerZones$ Battlefield | ValidCard$ Card.Self,Minotaur.nonToken+Other+YouCtrl | Execute$ TrigToken | TriggerDescription$ Whenever CARDNAME or another nontoken Minotaur enters enters the battlefield under your control, create a 2/3 red Minotaur creature token.
|
||||
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ r_2_3_minotaur | TokenOwner$ You
|
||||
A:AB$ PumpAll | Cost$ 2 BR | ValidCards$ Minotaur.YouCtrl | NumAtt$ +1 | KW$ Menace & Haste | SpellDescription$ Minotaurs you control get +1/+0 and gain menace and haste until end of turn.
|
||||
SVar:PlayMain1:TRUE
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
Name:Strength from the Fallen
|
||||
ManaCost:1 G
|
||||
Types:Enchantment
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPump | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, target creature gets +X/+X until end of turn, where X is the number of creature cards in your graveyard.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Enchantment.Other+YouCtrl | TriggerZones$ Battlefield | Secondary$ True | Execute$ TrigPump | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, target creature gets +X/+X until end of turn, where X is the number of creature cards in your graveyard.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.Other+YouCtrl | Execute$ TrigPump | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, target creature gets +X/+X until end of turn, where X is the number of creature cards in your graveyard.
|
||||
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature | NumAtt$ +X | NumDef$ +X
|
||||
SVar:X:Count$TypeInYourYard.Creature
|
||||
SVar:PlayMain1:TRUE
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Thassa's Devourer
|
||||
ManaCost:4 U
|
||||
Types:Enchantment Creature Elemental
|
||||
PT:2/6
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMill | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, target player mills two cards.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Enchantment.Other+YouCtrl | TriggerZones$ Battlefield | Secondary$ True | Execute$ TrigMill | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, target player mills two cards.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.Other+YouCtrl | Execute$ TrigMill | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment enters the battlefield under your control, target player mills two cards.
|
||||
SVar:TrigMill:DB$ Mill | ValidTgts$ Player | TgtPrompt$ Select target player | NumCards$ 2
|
||||
SVar:BuffedBy:Enchantment
|
||||
Oracle:Constellation — Whenever Thassa's Devourer or another enchantment enters the battlefield under your control, target player mills two cards.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user