Merge branch 'master' of https://github.com/Card-Forge/forge into adventure

This commit is contained in:
Grimm
2022-09-20 02:07:56 +02:00
73 changed files with 741 additions and 132 deletions

View File

@@ -25,6 +25,11 @@ public final class ImageKeys {
public static final String FORETELL_IMAGE = "foretell"; public static final String FORETELL_IMAGE = "foretell";
public static final String BACKFACE_POSTFIX = "$alt"; public static final String BACKFACE_POSTFIX = "$alt";
public static final String SPECFACE_W = "$wspec";
public static final String SPECFACE_U = "$uspec";
public static final String SPECFACE_B = "$bspec";
public static final String SPECFACE_R = "$rspec";
public static final String SPECFACE_G = "$gspec";
private static String CACHE_CARD_PICS_DIR, CACHE_TOKEN_PICS_DIR, CACHE_ICON_PICS_DIR, CACHE_BOOSTER_PICS_DIR, private static String CACHE_CARD_PICS_DIR, CACHE_TOKEN_PICS_DIR, CACHE_ICON_PICS_DIR, CACHE_BOOSTER_PICS_DIR,
CACHE_FATPACK_PICS_DIR, CACHE_BOOSTERBOX_PICS_DIR, CACHE_PRECON_PICS_DIR, CACHE_TOURNAMENTPACK_PICS_DIR; CACHE_FATPACK_PICS_DIR, CACHE_BOOSTERBOX_PICS_DIR, CACHE_PRECON_PICS_DIR, CACHE_TOURNAMENTPACK_PICS_DIR;

View File

@@ -803,7 +803,7 @@ public class StaticData {
} }
// check the front image // check the front image
imagePath = ImageUtil.getImageRelativePath(cp, false, true, false); imagePath = ImageUtil.getImageRelativePath(cp, "", true, false);
if (imagePath != null) { if (imagePath != null) {
File file = ImageKeys.getImageFile(imagePath); File file = ImageKeys.getImageFile(imagePath);
if (file == null && ImageKeys.hasSetLookup(imagePath)) if (file == null && ImageKeys.hasSetLookup(imagePath))
@@ -820,7 +820,7 @@ public class StaticData {
// check the back face // check the back face
if (cp.hasBackFace()) { if (cp.hasBackFace()) {
imagePath = ImageUtil.getImageRelativePath(cp, true, true, false); imagePath = ImageUtil.getImageRelativePath(cp, "back", true, false);
if (imagePath != null) { if (imagePath != null) {
File file = ImageKeys.getImageFile(imagePath); File file = ImageKeys.getImageFile(imagePath);
if (file == null && ImageKeys.hasSetLookup(imagePath)) if (file == null && ImageKeys.hasSetLookup(imagePath))

View File

@@ -240,5 +240,10 @@ public interface IPaperCard extends InventoryItem, Serializable {
boolean hasBackFace(); boolean hasBackFace();
String getCardImageKey(); String getCardImageKey();
String getCardAltImageKey(); String getCardAltImageKey();
String getCardWSpecImageKey();
String getCardUSpecImageKey();
String getCardBSpecImageKey();
String getCardRSpecImageKey();
String getCardGSpecImageKey();
} }

View File

@@ -320,7 +320,7 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
@Override @Override
public String getCardImageKey() { public String getCardImageKey() {
if (this.cardImageKey == null) if (this.cardImageKey == null)
this.cardImageKey = ImageUtil.getImageKey(this, false, true); this.cardImageKey = ImageUtil.getImageKey(this, "", true);
return cardImageKey; return cardImageKey;
} }
@@ -329,13 +329,73 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
public String getCardAltImageKey() { public String getCardAltImageKey() {
if (this.cardAltImageKey == null){ if (this.cardAltImageKey == null){
if (this.hasBackFace()) if (this.hasBackFace())
this.cardAltImageKey = ImageUtil.getImageKey(this, true, true); this.cardAltImageKey = ImageUtil.getImageKey(this, "back", true);
else // altImageKey will be the same as cardImageKey else // altImageKey will be the same as cardImageKey
this.cardAltImageKey = ImageUtil.getImageKey(this, false, true); this.cardAltImageKey = ImageUtil.getImageKey(this, "", true);
} }
return cardAltImageKey; return cardAltImageKey;
} }
private String cardWSpecImageKey = null;
@Override
public String getCardWSpecImageKey() {
if (this.cardWSpecImageKey == null) {
if (this.rules.getSplitType() == CardSplitType.Specialize)
this.cardWSpecImageKey = ImageUtil.getImageKey(this, "white", true);
else // just use cardImageKey
this.cardWSpecImageKey = ImageUtil.getImageKey(this, "", true);
}
return cardWSpecImageKey;
}
private String cardUSpecImageKey = null;
@Override
public String getCardUSpecImageKey() {
if (this.cardUSpecImageKey == null) {
if (this.rules.getSplitType() == CardSplitType.Specialize)
this.cardUSpecImageKey = ImageUtil.getImageKey(this, "blue", true);
else // just use cardImageKey
this.cardUSpecImageKey = ImageUtil.getImageKey(this, "", true);
}
return cardUSpecImageKey;
}
private String cardBSpecImageKey = null;
@Override
public String getCardBSpecImageKey() {
if (this.cardBSpecImageKey == null) {
if (this.rules.getSplitType() == CardSplitType.Specialize)
this.cardBSpecImageKey = ImageUtil.getImageKey(this, "black", true);
else // just use cardImageKey
this.cardBSpecImageKey = ImageUtil.getImageKey(this, "", true);
}
return cardBSpecImageKey;
}
private String cardRSpecImageKey = null;
@Override
public String getCardRSpecImageKey() {
if (this.cardRSpecImageKey == null) {
if (this.rules.getSplitType() == CardSplitType.Specialize)
this.cardRSpecImageKey = ImageUtil.getImageKey(this, "red", true);
else // just use cardImageKey
this.cardRSpecImageKey = ImageUtil.getImageKey(this, "", true);
}
return cardRSpecImageKey;
}
private String cardGSpecImageKey = null;
@Override
public String getCardGSpecImageKey() {
if (this.cardGSpecImageKey == null) {
if (this.rules.getSplitType() == CardSplitType.Specialize)
this.cardGSpecImageKey = ImageUtil.getImageKey(this, "green", true);
else // just use cardImageKey
this.cardGSpecImageKey = ImageUtil.getImageKey(this, "", true);
}
return cardGSpecImageKey;
}
@Override @Override
public boolean hasBackFace(){ public boolean hasBackFace(){
CardSplitType cst = this.rules.getSplitType(); CardSplitType cst = this.rules.getSplitType();

View File

@@ -169,6 +169,27 @@ public class PaperToken implements InventoryItemFromSet, IPaperCard {
return getImageKey(true); return getImageKey(true);
} }
@Override
public String getCardWSpecImageKey() {
return getImageKey(false);
}
@Override
public String getCardUSpecImageKey() {
return getImageKey(false);
}
@Override
public String getCardBSpecImageKey() {
return getImageKey(false);
}
@Override
public String getCardRSpecImageKey() {
return getImageKey(false);
}
@Override
public String getCardGSpecImageKey() {
return getImageKey(false);
}
// InventoryItem // InventoryItem
@Override @Override
public String getImageKey(boolean altState) { public String getImageKey(boolean altState) {

View File

@@ -26,8 +26,8 @@ public class ImageUtil {
return cp; return cp;
} }
public static String getImageRelativePath(PaperCard cp, boolean backFace, boolean includeSet, boolean isDownloadUrl) { public static String getImageRelativePath(PaperCard cp, String face, boolean includeSet, boolean isDownloadUrl) {
final String nameToUse = cp == null ? null : getNameToUse(cp, backFace); final String nameToUse = cp == null ? null : getNameToUse(cp, face);
if (nameToUse == null) { if (nameToUse == null) {
return null; return null;
} }
@@ -80,36 +80,55 @@ public class ImageUtil {
} }
} }
public static String getNameToUse(PaperCard cp, boolean backFace) { public static String getNameToUse(PaperCard cp, String face) {
final CardRules card = cp.getRules(); final CardRules card = cp.getRules();
if (backFace) { if (face.equals("back")) {
if (cp.hasBackFace()) if (cp.hasBackFace())
if (card.getOtherPart() != null) { if (card.getOtherPart() != null) {
return card.getOtherPart().getName(); return card.getOtherPart().getName();
} else if (!card.getMeldWith().isEmpty()) { } else if (!card.getMeldWith().isEmpty()) {
final CardDb db = StaticData.instance().getCommonCards(); final CardDb db = StaticData.instance().getCommonCards();
return db.getRules(card.getMeldWith()).getOtherPart().getName(); return db.getRules(card.getMeldWith()).getOtherPart().getName();
} else { } else {
return null; return null;
} }
else else
return null; return null;
} else if(CardSplitType.Split == cp.getRules().getSplitType()) { } else if (face.equals("white")) {
if (card.getWSpecialize() != null) {
return card.getWSpecialize().getName();
}
} else if (face.equals("blue")) {
if (card.getUSpecialize() != null) {
return card.getUSpecialize().getName();
}
} else if (face.equals("black")) {
if (card.getBSpecialize() != null) {
return card.getBSpecialize().getName();
}
} else if (face.equals("red")) {
if (card.getRSpecialize() != null) {
return card.getRSpecialize().getName();
}
} else if (face.equals("green")) {
if (card.getGSpecialize() != null) {
return card.getGSpecialize().getName();
}
} else if (CardSplitType.Split == cp.getRules().getSplitType()) {
return card.getMainPart().getName() + card.getOtherPart().getName(); return card.getMainPart().getName() + card.getOtherPart().getName();
} else {
return cp.getName();
} }
return cp.getName();
} }
public static String getImageKey(PaperCard cp, boolean backFace, boolean includeSet) { public static String getImageKey(PaperCard cp, String face, boolean includeSet) {
return getImageRelativePath(cp, backFace, includeSet, false); return getImageRelativePath(cp, face, includeSet, false);
} }
public static String getDownloadUrl(PaperCard cp, boolean backFace) { public static String getDownloadUrl(PaperCard cp, String face) {
return getImageRelativePath(cp, backFace, true, true); return getImageRelativePath(cp, face, true, true);
} }
public static String getScryfallDownloadUrl(PaperCard cp, boolean backFace, String setCode, String langCode, boolean useArtCrop){ public static String getScryfallDownloadUrl(PaperCard cp, String face, String setCode, String langCode, boolean useArtCrop){
String editionCode; String editionCode;
if ((setCode != null) && (setCode.length() > 0)) if ((setCode != null) && (setCode.length() > 0))
editionCode = setCode; editionCode = setCode;
@@ -121,7 +140,7 @@ public class ImageUtil {
String versionParam = useArtCrop ? "art_crop" : "normal"; String versionParam = useArtCrop ? "art_crop" : "normal";
String faceParam = ""; String faceParam = "";
if (cp.getRules().getOtherPart() != null) { if (cp.getRules().getOtherPart() != null) {
faceParam = (backFace ? "&face=back" : "&face=front"); faceParam = (face.equals("back") ? "&face=back" : "&face=front");
} }
return String.format("%s/%s/%s?format=image&version=%s%s", editionCode, cardCollectorNumber, return String.format("%s/%s/%s?format=image&version=%s%s", editionCode, cardCollectorNumber,
langCode, versionParam, faceParam); langCode, versionParam, faceParam);

View File

@@ -17,53 +17,19 @@
*/ */
package forge.game; package forge.game;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import forge.util.*;
import org.apache.commons.lang3.tuple.ImmutablePair;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.ComparisonChain; import com.google.common.collect.*;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets;
import com.google.common.collect.Table;
import forge.GameCommand; import forge.GameCommand;
import forge.StaticData; import forge.StaticData;
import forge.card.CardStateName; import forge.card.CardStateName;
import forge.card.MagicColor;
import forge.deck.DeckSection; import forge.deck.DeckSection;
import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.Card; import forge.game.card.*;
import forge.game.card.CardCollection; import forge.game.event.*;
import forge.game.card.CardCollectionView;
import forge.game.card.CardDamageMap;
import forge.game.card.CardFactory;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardUtil;
import forge.game.card.CardZoneTable;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.event.GameEventCardChangeZone;
import forge.game.event.GameEventCardDestroyed;
import forge.game.event.GameEventCardStatsChanged;
import forge.game.event.GameEventCardTapped;
import forge.game.event.GameEventFlipCoin;
import forge.game.event.GameEventGameStarted;
import forge.game.event.GameEventScry;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
import forge.game.keyword.KeywordInterface; import forge.game.keyword.KeywordInterface;
import forge.game.keyword.KeywordsChange; import forge.game.keyword.KeywordsChange;
@@ -87,8 +53,12 @@ import forge.game.zone.PlayerZoneBattlefield;
import forge.game.zone.Zone; import forge.game.zone.Zone;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.util.*;
import forge.util.collect.FCollection; import forge.util.collect.FCollection;
import forge.util.collect.FCollectionView; import forge.util.collect.FCollectionView;
import org.apache.commons.lang3.tuple.ImmutablePair;
import java.util.*;
/** /**
* Methods for common actions performed during a game. * Methods for common actions performed during a game.
@@ -2148,6 +2118,13 @@ public class GameAction {
return input.getName().equals("Emissary's Ploy"); return input.getName().equals("Emissary's Ploy");
} }
}); });
CardCollectionView all = CardLists.filterControlledBy(game.getCardsInGame(), takesAction);
List<Card> spires = CardLists.filter(all, new Predicate<Card>() {
@Override
public boolean apply(Card input) {
return input.getName().equals("Cryptic Spires");
}
});
int chosen = 1; int chosen = 1;
List<Integer> cmc = Lists.newArrayList(1, 2, 3); List<Integer> cmc = Lists.newArrayList(1, 2, 3);
@@ -2160,6 +2137,17 @@ public class GameAction {
c.setChosenNumber(chosen); c.setChosenNumber(chosen);
} }
for (Card c : spires) {
if (!c.hasChosenColor()) {
List<String> colorChoices = new ArrayList<>(MagicColor.Constant.ONLY_COLORS);
String prompt = CardTranslation.getTranslatedName(c.getName()) + ": " +
Localizer.getInstance().getMessage("lblChooseNColors", Lang.getNumeral(2));
SpellAbility sa = new SpellAbility.EmptySa(ApiType.ChooseColor, c, takesAction);
sa.putParam("AILogic", "MostProminentInComputerDeck");
List<String> chosenColors = takesAction.getController().chooseColors(prompt, sa, 2, 2, colorChoices);
c.setChosenColors(chosenColors);
}
}
takesAction = game.getNextPlayerAfter(takesAction); takesAction = game.getNextPlayerAfter(takesAction);
} while (takesAction != first); } while (takesAction != first);
} }

View File

@@ -101,6 +101,7 @@ public class ChooseCardEffect extends SpellAbilityEffect {
} }
for (final Player p : tgtPlayers) { for (final Player p : tgtPlayers) {
boolean dontRevealToOwner = true;
if (sa.hasParam("EachBasicType")) { if (sa.hasParam("EachBasicType")) {
// Get all lands, // Get all lands,
List<Card> land = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.LANDS); List<Card> land = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.LANDS);
@@ -220,6 +221,7 @@ public class ChooseCardEffect extends SpellAbilityEffect {
} else if ((tgt == null) || p.canBeTargetedBy(sa)) { } else if ((tgt == null) || p.canBeTargetedBy(sa)) {
if (sa.hasParam("AtRandom") && !choices.isEmpty()) { if (sa.hasParam("AtRandom") && !choices.isEmpty()) {
Aggregates.random(choices, validAmount, chosen); Aggregates.random(choices, validAmount, chosen);
dontRevealToOwner = false;
} else { } else {
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") + " "; String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") + " ";
if (sa.hasParam ("ChoiceTitleAppendDefined")) { if (sa.hasParam ("ChoiceTitleAppendDefined")) {
@@ -248,12 +250,14 @@ public class ChooseCardEffect extends SpellAbilityEffect {
} }
} }
if (sa.hasParam("Reveal") && !sa.hasParam("SecretlyChoose")) { if (sa.hasParam("Reveal") && !sa.hasParam("SecretlyChoose")) {
game.getAction().reveal(chosen, p, true, sa.hasParam("RevealTitle") ? sa.getParam("RevealTitle") : Localizer.getInstance().getMessage("lblChosenCards") + " "); game.getAction().reveal(chosen, p, dontRevealToOwner, sa.hasParam("RevealTitle") ?
sa.getParam("RevealTitle") : Localizer.getInstance().getMessage("lblChosenCards") + " ");
} }
} }
if(sa.hasParam("Reveal") && sa.hasParam("SecretlyChoose")) { if (sa.hasParam("Reveal") && sa.hasParam("SecretlyChoose")) {
for (final Player p : tgtPlayers) { for (final Player p : tgtPlayers) {
game.getAction().reveal(chosen, p, true, sa.hasParam("RevealTitle") ? sa.getParam("RevealTitle") : Localizer.getInstance().getMessage("lblChosenCards") + " "); game.getAction().reveal(chosen, p, true, sa.hasParam("RevealTitle") ?
sa.getParam("RevealTitle") : Localizer.getInstance().getMessage("lblChosenCards") + " ");
} }
} }
host.setChosenCards(chosen); host.setChosenCards(chosen);

View File

@@ -27,7 +27,7 @@ public class ChooseTypeEffect extends SpellAbilityEffect {
for (final Player p : getTargetPlayers(sa)) { for (final Player p : getTargetPlayers(sa)) {
sb.append(p); sb.append(p);
} }
sb.append(" chooses a type."); sb.append(" chooses a ").append(sa.getParam("Type").toLowerCase()).append(" type.");
} else { } else {
sb.append("Please improve the stack description."); sb.append("Please improve the stack description.");
} }

View File

@@ -360,10 +360,15 @@ public class PlayEffect extends SpellAbilityEffect {
tgtSA = tgtSA.copyWithNoManaCost(); tgtSA = tgtSA.copyWithNoManaCost();
} else if (sa.hasParam("PlayCost")) { } else if (sa.hasParam("PlayCost")) {
Cost abCost; Cost abCost;
if ("ManaCost".equals(sa.getParam("PlayCost"))) { String cost = sa.getParam("PlayCost");
if (cost.equals("ManaCost")) {
abCost = new Cost(source.getManaCost(), false); abCost = new Cost(source.getManaCost(), false);
} else { } else {
abCost = new Cost(sa.getParam("PlayCost"), false); if (cost.contains("ConvertedManaCost")) {
final String costcmc = Integer.toString(tgtCard.getCMC());
cost = cost.replace("ConvertedManaCost", costcmc);
}
abCost = new Cost(cost, false);
} }
tgtSA = tgtSA.copyWithDefinedCost(abCost); tgtSA = tgtSA.copyWithDefinedCost(abCost);

View File

@@ -280,6 +280,27 @@ public class CardFactory {
} else if (c.isAdventureCard()) { } else if (c.isAdventureCard()) {
c.setState(CardStateName.Adventure, false); c.setState(CardStateName.Adventure, false);
c.setImageKey(originalPicture); c.setImageKey(originalPicture);
} else if (c.canSpecialize()) {
c.setState(CardStateName.SpecializeW, false);
c.setImageKey(cp.getImageKey(false) + ImageKeys.SPECFACE_W);
c.setSetCode(cp.getEdition());
c.setRarity(cp.getRarity());
c.setState(CardStateName.SpecializeU, false);
c.setImageKey(cp.getImageKey(false) + ImageKeys.SPECFACE_U);
c.setSetCode(cp.getEdition());
c.setRarity(cp.getRarity());
c.setState(CardStateName.SpecializeB, false);
c.setImageKey(cp.getImageKey(false) + ImageKeys.SPECFACE_B);
c.setSetCode(cp.getEdition());
c.setRarity(cp.getRarity());
c.setState(CardStateName.SpecializeR, false);
c.setImageKey(cp.getImageKey(false) + ImageKeys.SPECFACE_R);
c.setSetCode(cp.getEdition());
c.setRarity(cp.getRarity());
c.setState(CardStateName.SpecializeG, false);
c.setImageKey(cp.getImageKey(false) + ImageKeys.SPECFACE_G);
c.setSetCode(cp.getEdition());
c.setRarity(cp.getRarity());
} }
c.setSetCode(cp.getEdition()); c.setSetCode(cp.getEdition());

View File

@@ -26,6 +26,7 @@ import forge.game.card.CardPredicates.Presets;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.Lang;
import forge.util.TextUtil; import forge.util.TextUtil;
/** /**
@@ -114,7 +115,7 @@ public class CostTapType extends CostPartWithList {
sb.append(" you control"); sb.append(" you control");
} }
} else { } else {
sb.append(Cost.convertAmountTypeToWords(i, this.getAmount(), "untapped " + desc)).append(" you control"); sb.append(Lang.nounWithNumeralExceptOne(this.getAmount(), "untapped " + desc)).append(" you control");
} }
return sb.toString(); return sb.toString();
} }

View File

@@ -172,12 +172,48 @@ public class ImageCache {
IPaperCard ipc = null; IPaperCard ipc = null;
boolean altState = imageKey.endsWith(ImageKeys.BACKFACE_POSTFIX); boolean altState = imageKey.endsWith(ImageKeys.BACKFACE_POSTFIX);
String specColor = "";
if (imageKey.endsWith(ImageKeys.SPECFACE_W)) {
specColor = "white";
} else if (imageKey.endsWith(ImageKeys.SPECFACE_U)) {
specColor = "blue";
} else if (imageKey.endsWith(ImageKeys.SPECFACE_B)) {
specColor = "black";
} else if (imageKey.endsWith(ImageKeys.SPECFACE_R)) {
specColor = "red";
} else if (imageKey.endsWith(ImageKeys.SPECFACE_G)) {
specColor = "green";
}
if (altState) if (altState)
imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.BACKFACE_POSTFIX.length()); imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.BACKFACE_POSTFIX.length());
if (!specColor.equals(""))
imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.SPECFACE_W.length());
if (imageKey.startsWith(ImageKeys.CARD_PREFIX)) { if (imageKey.startsWith(ImageKeys.CARD_PREFIX)) {
ipc = ImageUtil.getPaperCardFromImageKey(imageKey); ipc = ImageUtil.getPaperCardFromImageKey(imageKey);
if (ipc != null) { if (ipc != null) {
imageKey = altState ? ipc.getCardAltImageKey() : ipc.getCardImageKey(); if (altState) {
imageKey = ipc.getCardAltImageKey();
} else if (!specColor.equals("")) {
switch (specColor) {
case "white":
imageKey = ipc.getCardWSpecImageKey();
break;
case "blue":
imageKey = ipc.getCardUSpecImageKey();
break;
case "black":
imageKey = ipc.getCardBSpecImageKey();
break;
case "red":
imageKey = ipc.getCardRSpecImageKey();
break;
case "green":
imageKey = ipc.getCardGSpecImageKey();
break;
}
} else {
imageKey = ipc.getCardImageKey();
}
if (StringUtils.isBlank(imageKey)) if (StringUtils.isBlank(imageKey))
return Pair.of(_defaultImage, true); return Pair.of(_defaultImage, true);
} }

View File

@@ -73,7 +73,7 @@ public class DeckHtmlSerializer {
// System.out.println(card.getSets().get(card.getSets().size() - 1).URL); // System.out.println(card.getSets().get(card.getSets().size() - 1).URL);
for (int i = card.getValue(); i > 0; --i ) { for (int i = card.getValue(); i > 0; --i ) {
final PaperCard r = card.getKey(); final PaperCard r = card.getKey();
final String url = ForgeConstants.URL_PIC_DOWNLOAD + ImageUtil.getDownloadUrl(r, false); final String url = ForgeConstants.URL_PIC_DOWNLOAD + ImageUtil.getDownloadUrl(r, "");
list.add(url); list.add(url);
} }
} }

View File

@@ -77,15 +77,51 @@ public final class FImageUtil {
} }
boolean altState = key.endsWith(ImageKeys.BACKFACE_POSTFIX); boolean altState = key.endsWith(ImageKeys.BACKFACE_POSTFIX);
String specColor = "";
if (key.endsWith(ImageKeys.SPECFACE_W)) {
specColor = "white";
} else if (key.endsWith(ImageKeys.SPECFACE_U)) {
specColor = "blue";
} else if (key.endsWith(ImageKeys.SPECFACE_B)) {
specColor = "black";
} else if (key.endsWith(ImageKeys.SPECFACE_R)) {
specColor = "red";
} else if (key.endsWith(ImageKeys.SPECFACE_G)) {
specColor = "green";
}
String imageKey = key; String imageKey = key;
if (prefix.equals(ImageKeys.CARD_PREFIX)) { if (prefix.equals(ImageKeys.CARD_PREFIX)) {
PaperCard card = ImageUtil.getPaperCardFromImageKey(key); PaperCard card = ImageUtil.getPaperCardFromImageKey(key);
if (card != null) if (altState) {
imageKey = altState ? card.getCardAltImageKey() : card.getCardImageKey(); imageKey = card.getCardAltImageKey();
} else if (!specColor.equals("")) {
switch (specColor) {
case "white":
imageKey = card.getCardWSpecImageKey();
break;
case "blue":
imageKey = card.getCardUSpecImageKey();
break;
case "black":
imageKey = card.getCardBSpecImageKey();
break;
case "red":
imageKey = card.getCardRSpecImageKey();
break;
case "green":
imageKey = card.getCardGSpecImageKey();
break;
}
} else {
imageKey = card.getCardImageKey();
}
} }
if(altState) { if(altState) {
imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.BACKFACE_POSTFIX.length()); imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.BACKFACE_POSTFIX.length());
imageKey += "full.jpg"; imageKey += "full.jpg";
} else if (!specColor.equals("")) {
imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.SPECFACE_W.length());
imageKey += "full.jpg";
} }
File file = ImageKeys.getImageFile(imageKey); File file = ImageKeys.getImageFile(imageKey);

View File

@@ -92,7 +92,7 @@ public class NewGameScene extends UIScene {
mode.addListener(new ChangeListener() { mode.addListener(new ChangeListener() {
@Override @Override
public void changed(ChangeEvent changeEvent, Actor actor) { public void changed(ChangeEvent changeEvent, Actor actor) {
colorLabel.setText(mode.getCurrentIndex() < 2 ? colorIdLabel : Forge.getLocalizer().getMessage("lblDeck")+":"); colorLabel.setText(mode.getCurrentIndex() < 2 ? colorIdLabel : "[BLACK]"+Forge.getLocalizer().getMessage("lblDeck")+":");
if (mode.getCurrentIndex() == 3) if (mode.getCurrentIndex() == 3)
colorId.setTextList(custom); colorId.setTextList(custom);
if (mode.getCurrentIndex() == 2) if (mode.getCurrentIndex() == 2)

View File

@@ -107,13 +107,8 @@ public class SaveLoadScene extends UIScene {
difficulty.setSelectedIndex(1); difficulty.setSelectedIndex(1);
difficulty.setAlignment(Align.center); difficulty.setAlignment(Align.center);
difficulty.getStyle().fontColor = Color.GOLD; difficulty.getStyle().fontColor = Color.GOLD;
if (Forge.isLandscapeMode()) { difficulty.setX(scrollPane.getWidth()-difficulty.getWidth()+5);
difficulty.setX(280); difficulty.setY(scrollPane.getTop()-difficulty.getHeight()-5);
difficulty.setY(220);
} else {
difficulty.setX(190);
difficulty.setY(336);
}
} }

View File

@@ -183,7 +183,7 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb
} }
} }
} else { } else {
String imagePath = ImageUtil.getImageRelativePath(reward.getCard(), false, true, false); String imagePath = ImageUtil.getImageRelativePath(reward.getCard(), "", true, false);
File lookup = ImageKeys.hasSetLookup(imagePath) ? ImageKeys.setLookUpFile(imagePath, imagePath+"border") : null; File lookup = ImageKeys.hasSetLookup(imagePath) ? ImageKeys.setLookUpFile(imagePath, imagePath+"border") : null;
int count = 0; int count = 0;
if (lookup != null) { if (lookup != null) {

View File

@@ -711,13 +711,26 @@ public class World implements Disposable, SaveFileContent {
} }
for(Map.Entry<String, Pair<Pixmap, HashMap<String, Pixmap>>> entry:pixmapHash.entrySet()) for(Map.Entry<String, Pair<Pixmap, HashMap<String, Pixmap>>> entry:pixmapHash.entrySet())
{ {
entry.getValue().getLeft().dispose(); try {
entry.getValue().getLeft().dispose();
} catch (Exception e) {
e.printStackTrace();
}
for(Map.Entry<String, Pixmap> pairEntry:entry.getValue().getRight().entrySet()) for(Map.Entry<String, Pixmap> pairEntry:entry.getValue().getRight().entrySet())
{ {
pairEntry.getValue().dispose(); try {
pairEntry.getValue().dispose();
} catch (Exception e) {
e.printStackTrace();
}
} }
} }
drawPixmapNow(pix); pixmapHash.clear();
try {
drawPixmapNow(pix);
} catch (Exception e) {
e.printStackTrace();
}
currentTime[0] = measureGenerationTime("mini map", currentTime[0]); currentTime[0] = measureGenerationTime("mini map", currentTime[0]);

View File

@@ -62,7 +62,16 @@
"width": 64, "width": 64,
"height": 16, "height": 16,
"x": 442, "x": 442,
"y": 64 "y": 56
},
{
"type": "Label",
"name": "mana",
"font": "default",
"width": 64,
"height": 16,
"x": 442,
"y": 73
}, },
{ {
"type": "Label", "type": "Label",
@@ -71,7 +80,7 @@
"width": 64, "width": 64,
"height": 16, "height": 16,
"x": 442, "x": 442,
"y": 82 "y": 90
}, },
{ {
"type": "TextButton", "type": "TextButton",

View File

@@ -5,5 +5,5 @@ PT:1/3
K:Flying K:Flying
S:Mode$ Continuous | Affected$ Creature.attacking ChosenPlayer | AddPower$ 1 | Description$ Creatures attacking the last chosen player get +1/+0. S:Mode$ Continuous | Affected$ Creature.attacking ChosenPlayer | AddPower$ 1 | Description$ Creatures attacking the last chosen player get +1/+0.
T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | Execute$ TrigChoose | TriggerZones$ Battlefield | TriggerDescription$ Lure the Unwary — At the beginning of combat on your turn, choose an opponent. T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | Execute$ TrigChoose | TriggerZones$ Battlefield | TriggerDescription$ Lure the Unwary — At the beginning of combat on your turn, choose an opponent.
SVar:TrigChoose:DB$ ChoosePlayer | Defined$ You | Choices$ Player.Opponent | SetChosenPlayer$ True SVar:TrigChoose:DB$ ChoosePlayer | Defined$ You | Choices$ Player.Opponent
Oracle:Flying\nLure the Unwary — At the beginning of combat on your turn, choose an opponent.\nCreatures attacking the last chosen player get +1/+0. Oracle:Flying\nLure the Unwary — At the beginning of combat on your turn, choose an opponent.\nCreatures attacking the last chosen player get +1/+0.

View File

@@ -4,5 +4,5 @@ Types:Artifact Creature Griffin
PT:3/2 PT:3/2
K:Flying K:Flying
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigDestroy | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, destroy target nonland permanent of that player's choice that one of your opponents controls. T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigDestroy | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, destroy target nonland permanent of that player's choice that one of your opponents controls.
SVar:TrigDestroy:DB$ Destroy | TargetingPlayer$ TriggeredTarget | ValidTgts$ Permanent.nonLand+OppCtrl SVar:TrigDestroy:DB$ Destroy | TargetingPlayer$ TriggeredTarget | ValidTgts$ Permanent.nonLand+OppCtrl | TgtPrompt$ Select target nonland permanent controlled by opponent of damaging player
Oracle:Flying\nWhenever Bladegriff Prototype deals combat damage to a player, destroy target nonland permanent of that player's choice that one of your opponents controls. Oracle:Flying\nWhenever Bladegriff Prototype deals combat damage to a player, destroy target nonland permanent of that player's choice that one of your opponents controls.

View File

@@ -4,5 +4,6 @@ Types:Creature Phyrexian Human Cleric
PT:2/2 PT:2/2
K:Intimidate K:Intimidate
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigDestroy | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may sacrifice it. If you do, destroy target creature that player controls. T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigDestroy | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may sacrifice it. If you do, destroy target creature that player controls.
SVar:TrigDestroy:AB$ Destroy | Cost$ Sac<1/CARDNAME> | ValidTgts$ Creature.ControlledBy TriggeredDefendingPlayer | AITgts$ BetterThanSource | TgtPrompt$ Select target creature defending player controls SVar:TrigDestroy:AB$ Destroy | Cost$ Sac<1/CARDNAME> | ValidTgts$ Creature.ControlledBy TriggeredTarget | AITgts$ BetterThanSource | TgtPrompt$ Select target creature damaged player controls
DeckHas:Ability$Sacrifice
Oracle:Intimidate (This creature can't be blocked except by artifact creatures and/or creatures that share a color with it.)\nWhenever Blind Zealot deals combat damage to a player, you may sacrifice it. If you do, destroy target creature that player controls. Oracle:Intimidate (This creature can't be blocked except by artifact creatures and/or creatures that share a color with it.)\nWhenever Blind Zealot deals combat damage to a player, you may sacrifice it. If you do, destroy target creature that player controls.

View File

@@ -3,10 +3,9 @@ ManaCost:4 R R
Types:Creature Efreet Types:Creature Efreet
PT:6/4 PT:6/4
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ At the beginning of your upkeep, choose target nonland permanent you control and up to two target nonland permanents you don't control. Destroy one of them at random. T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ At the beginning of your upkeep, choose target nonland permanent you control and up to two target nonland permanents you don't control. Destroy one of them at random.
SVar:TrigPump:DB$ Pump | ValidTgts$ Permanent.nonLand+YouCtrl | TgtPrompt$ Select target nonland permanent you control | Mandatory$ True | RememberObjects$ Targeted | IsCurse$ True | SubAbility$ DBPump | StackDescription$ None SVar:TrigPump:DB$ Pump | ValidTgts$ Permanent.nonLand+YouCtrl | TgtPrompt$ Select target nonland permanent you control | Mandatory$ True | IsCurse$ True | SubAbility$ DBPump
SVar:DBPump:DB$ Pump | ValidTgts$ Permanent.nonLand+YouDontCtrl | TgtPrompt$ Select target nonland permanent you don't control | TargetMin$ 0 | TargetMax$ 1 | RememberObjects$ Targeted | IsCurse$ True | SubAbility$ DBPump2 | StackDescription$ None SVar:DBPump:DB$ Pump | ValidTgts$ Permanent.nonLand+YouDontCtrl | TgtPrompt$ Select up to two target nonland permanents you don't control | TargetMin$ 0 | TargetMax$ 2 | IsCurse$ True | SubAbility$ DBChooseRandom
SVar:DBPump2:DB$ Pump | ValidTgts$ Permanent.nonLand+YouDontCtrl | TgtPrompt$ Select another target nonland permanent you don't control | TargetMin$ 0 | TargetMax$ 1 | TargetUnique$ True | RememberObjects$ Targeted | IsCurse$ True | SubAbility$ DBChooseRandom | StackDescription$ None SVar:DBChooseRandom:DB$ ChooseCard | AtRandom$ True | Reveal$ True | RevealTitle$ OVERRIDE Randomly chosen permanent: | DefinedCards$ TargetedCard | SubAbility$ DBDestroy
SVar:DBChooseRandom:DB$ ChooseCard | Defined$ You | Amount$ 1 | AtRandom$ True | Choices$ Card.IsRemembered | SubAbility$ DBDestroy
SVar:DBDestroy:DB$ Destroy | Defined$ ChosenCard | SubAbility$ DBCleanup SVar:DBDestroy:DB$ Destroy | Defined$ ChosenCard | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True
Oracle:At the beginning of your upkeep, choose target nonland permanent you control and up to two target nonland permanents you don't control. Destroy one of them at random. Oracle:At the beginning of your upkeep, choose target nonland permanent you control and up to two target nonland permanents you don't control. Destroy one of them at random.

View File

@@ -4,5 +4,5 @@ Types:Creature Insect
PT:1/1 PT:1/1
K:Flying K:Flying
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigDestroy | CombatDamage$ True | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may destroy target artifact that player controls. T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigDestroy | CombatDamage$ True | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may destroy target artifact that player controls.
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select an artifact your opponent controls. SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredTarget | TgtPrompt$ Select target artifact damaged player controls
Oracle:Flying\nWhenever Caustic Wasps deals combat damage to a player, you may destroy target artifact that player controls. Oracle:Flying\nWhenever Caustic Wasps deals combat damage to a player, you may destroy target artifact that player controls.

View File

@@ -3,7 +3,7 @@ ManaCost:3 B R G
Types:Legendary Creature Dragon Types:Legendary Creature Dragon
PT:6/6 PT:6/6
K:Flying K:Flying
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | OptionalDecider$ You | Execute$ TrigChooseColor | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may pay {2}{R}. If you do, choose a color, then that player reveals their hand and Darigaaz deals damage to the player equal to the number of cards of that color revealed this way. T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | OptionalDecider$ You | Execute$ TrigChooseColor | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may pay {2}{R}. If you do, choose a color, then that player reveals their hand and NICKNAME deals damage to the player equal to the number of cards of that color revealed this way.
SVar:TrigChooseColor:AB$ ChooseColor | Cost$ 2 R | Defined$ You | AILogic$ MostProminentInHumanDeck | SubAbility$ DBRevealHand SVar:TrigChooseColor:AB$ ChooseColor | Cost$ 2 R | Defined$ You | AILogic$ MostProminentInHumanDeck | SubAbility$ DBRevealHand
SVar:DBRevealHand:DB$ RevealHand | Defined$ TriggeredTarget | RememberRevealed$ True | SubAbility$ DBDamage SVar:DBRevealHand:DB$ RevealHand | Defined$ TriggeredTarget | RememberRevealed$ True | SubAbility$ DBDamage
SVar:DBDamage:DB$ DealDamage | Defined$ TriggeredTarget | NumDmg$ X | SubAbility$ DBCleanup SVar:DBDamage:DB$ DealDamage | Defined$ TriggeredTarget | NumDmg$ X | SubAbility$ DBCleanup

View File

@@ -4,5 +4,5 @@ Types:Creature Human Cleric
PT:2/2 PT:2/2
K:Morph:1 W K:Morph:1 W
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigDestroy | CombatDamage$ True | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may destroy target enchantment that player controls. T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigDestroy | CombatDamage$ True | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may destroy target enchantment that player controls.
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Enchantment.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select an enchantment your opponent controls. SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Enchantment.ControlledBy TriggeredTarget | TgtPrompt$ Select target artifact damaged player controls
Oracle:Whenever Dawning Purist deals combat damage to a player, you may destroy target enchantment that player controls.\nMorph {1}{W} (You may cast this card face down as a 2/2 creature for {3}. Turn it face up any time for its morph cost.) Oracle:Whenever Dawning Purist deals combat damage to a player, you may destroy target enchantment that player controls.\nMorph {1}{W} (You may cast this card face down as a 2/2 creature for {3}. Turn it face up any time for its morph cost.)

View File

@@ -5,7 +5,7 @@ PT:2/1
K:Ninjutsu:1 B K:Ninjutsu:1 B
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigImmediateTrig | CombatDamage$ True | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may discard a creature card. When you do, destroy target creature or planeswalker that player controls. T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigImmediateTrig | CombatDamage$ True | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may discard a creature card. When you do, destroy target creature or planeswalker that player controls.
SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ Discard<1/Creature> | Execute$ TrigDestroy | CopyTriggeringObjects$ True | TriggerDescription$ When you do, destroy target creature or planeswalker that player controls. SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ Discard<1/Creature> | Execute$ TrigDestroy | CopyTriggeringObjects$ True | TriggerDescription$ When you do, destroy target creature or planeswalker that player controls.
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Creature.ControlledBy TriggeredDefendingPlayer,Planeswalker.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select target creature or planeswalker that player controls SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Creature.ControlledBy TriggeredTarget,Planeswalker.ControlledBy TriggeredTarget | TgtPrompt$ Select target creature or planeswalker damaged player controls
DeckHas:Ability$Discard DeckHas:Ability$Discard
SVar:AIPreference:DiscardCost$Creature.cmcLE3 SVar:AIPreference:DiscardCost$Creature.cmcLE3
Oracle:Ninjutsu {1}{B} ({1}{B}, Return an unblocked attacker you control to hand: Put this card onto the battlefield from your hand tapped and attacking.)\nWhenever Dokuchi Silencer deals combat damage to a player, you may discard a creature card. When you do, destroy target creature or planeswalker that player controls. Oracle:Ninjutsu {1}{B} ({1}{B}, Return an unblocked attacker you control to hand: Put this card onto the battlefield from your hand tapped and attacking.)\nWhenever Dokuchi Silencer deals combat damage to a player, you may discard a creature card. When you do, destroy target creature or planeswalker that player controls.

View File

@@ -7,5 +7,5 @@ T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.S
SVar:TrigToken:AB$ Token | Cost$ 2 | TokenScript$ g_1_1_elf_warrior | RememberTokens$ True | SubAbility$ DBAttach SVar:TrigToken:AB$ Token | Cost$ 2 | TokenScript$ g_1_1_elf_warrior | RememberTokens$ True | SubAbility$ DBAttach
SVar:DBAttach:DB$ Attach | Object$ TriggeredCard | Defined$ Remembered | SubAbility$ DBCleanup SVar:DBAttach:DB$ Attach | Object$ TriggeredCard | Defined$ Remembered | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
DeckHas:Ability$Token DeckHas:Ability$Token & Type$Elf|Warrior
Oracle:When Elven Bow enters the battlefield, you may pay {2}. If you do, create a 1/1 green Elf Warrior creature token, then attach Elven Bow to it.\nEquipped creature gets +1/+2 and has reach.\nEquip {3} Oracle:When Elven Bow enters the battlefield, you may pay {2}. If you do, create a 1/1 green Elf Warrior creature token, then attach Elven Bow to it.\nEquipped creature gets +1/+2 and has reach.\nEquip {3}

View File

@@ -4,5 +4,5 @@ Types:Artifact Equipment
K:Equip:2 K:Equip:2
S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 2 | Description$ Equipped creature gets +2/+0. S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 2 | Description$ Equipped creature gets +2/+0.
T:Mode$ DamageDone | ValidSource$ Creature.EquippedBy | ValidTarget$ Player | CombatDamage$ True | OptionalDecider$ You | Execute$ TrigDestroy | TriggerZones$ Battlefield | TriggerDescription$ Whenever equipped creature deals combat damage to a player, you may destroy target Equipment that player controls. T:Mode$ DamageDone | ValidSource$ Creature.EquippedBy | ValidTarget$ Player | CombatDamage$ True | OptionalDecider$ You | Execute$ TrigDestroy | TriggerZones$ Battlefield | TriggerDescription$ Whenever equipped creature deals combat damage to a player, you may destroy target Equipment that player controls.
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Equipment.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select target equipment defending player controls SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Equipment.ControlledBy TriggeredTarget | TgtPrompt$ Select target Equipment damaged player controls
Oracle:Equipped creature gets +2/+0.\nWhenever equipped creature deals combat damage to a player, you may destroy target Equipment that player controls.\nEquip {2} Oracle:Equipped creature gets +2/+0.\nWhenever equipped creature deals combat damage to a player, you may destroy target Equipment that player controls.\nEquip {2}

View File

@@ -3,7 +3,7 @@ ManaCost:1 R
Types:Enchantment Aura Types:Enchantment Aura
K:Flash K:Flash
K:Enchant creature K:Enchant creature
A:SP$ Attach | Cost$ 1 R | ValidTgts$ Creature | AITgts$ Card.powerGE1 | AILogic$ Pump A:SP$ Attach | ValidTgts$ Creature | AITgts$ Card.powerGE1 | AILogic$ Pump
T:Mode$ DamageDone | ValidSource$ Card.AttachedBy | ValidTarget$ Player.TriggeredDefendingPlayer | CombatDamage$ True | Execute$ TrigDestroy | OptionalDecider$ You | TriggerDescription$ Whenever enchanted creature deals combat damage to defending player, you may destroy target artifact that player controls. T:Mode$ DamageDone | ValidSource$ Card.AttachedBy | ValidTarget$ Player.TriggeredDefendingPlayer | CombatDamage$ True | Execute$ TrigDestroy | OptionalDecider$ You | TriggerDescription$ Whenever enchanted creature deals combat damage to defending player, you may destroy target artifact that player controls.
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select target artifact SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredTarget | TgtPrompt$ Select target artifact damaged player controls
Oracle:Flash\nEnchant creature\nWhenever enchanted creature deals combat damage to defending player, you may destroy target artifact that player controls. Oracle:Flash\nEnchant creature\nWhenever enchanted creature deals combat damage to defending player, you may destroy target artifact that player controls.

View File

@@ -4,9 +4,9 @@ Types:Legendary Creature Avatar Minion
PT:4/4 PT:4/4
T:Mode$ ChangesZone | ValidCard$ Card.wasNotCastFromYourHandByYou+Self | Destination$ Battlefield | Execute$ TrigYouLose | TriggerDescription$ When CARDNAME enters the battlefield, if you didn't cast it from your hand, you lose the game. T:Mode$ ChangesZone | ValidCard$ Card.wasNotCastFromYourHandByYou+Self | Destination$ Battlefield | Execute$ TrigYouLose | TriggerDescription$ When CARDNAME enters the battlefield, if you didn't cast it from your hand, you lose the game.
SVar:TrigYouLose:DB$ LosesGame | Defined$ You SVar:TrigYouLose:DB$ LosesGame | Defined$ You
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Creature | CombatDamage$ True | Execute$ TrigDestroy | TriggerDescription$ Whenever CARDNAME deals combat damage to a creature, destroy that creature. It can't be regenerated. T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Creature | CombatDamage$ True | Execute$ TrigDestroy | TriggerDescription$ Whenever NICKNAME deals combat damage to a creature, destroy that creature. It can't be regenerated.
SVar:TrigDestroy:DB$ Destroy | Defined$ TriggeredTargetLKICopy | NoRegen$ True SVar:TrigDestroy:DB$ Destroy | Defined$ TriggeredTargetLKICopy | NoRegen$ True
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigTheyLose | TriggerDescription$ Whenever Phage deals combat damage to a player, that player loses the game. T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigTheyLose | TriggerDescription$ Whenever NICKNAME deals combat damage to a player, that player loses the game.
SVar:TrigTheyLose:DB$ LosesGame | Defined$ TriggeredTarget SVar:TrigTheyLose:DB$ LosesGame | Defined$ TriggeredTarget
SVar:MustBeBlocked:True SVar:MustBeBlocked:True
Oracle:When Phage the Untouchable enters the battlefield, if you didn't cast it from your hand, you lose the game.\nWhenever Phage deals combat damage to a creature, destroy that creature. It can't be regenerated.\nWhenever Phage deals combat damage to a player, that player loses the game. Oracle:When Phage the Untouchable enters the battlefield, if you didn't cast it from your hand, you lose the game.\nWhenever Phage deals combat damage to a creature, destroy that creature. It can't be regenerated.\nWhenever Phage deals combat damage to a player, that player loses the game.

View File

@@ -6,6 +6,6 @@ K:Trample
K:Protection from enchantments K:Protection from enchantments
K:Monstrosity:3:4 R G K:Monstrosity:3:4 R G
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | IsPresent$ Card.Self+IsMonstrous | Execute$ TrigDestroy | CombatDamage$ True | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, if CARDNAME is monstrous, destroy target enchantment that player controls. T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | IsPresent$ Card.Self+IsMonstrous | Execute$ TrigDestroy | CombatDamage$ True | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, if CARDNAME is monstrous, destroy target enchantment that player controls.
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Enchantment | TgtPrompt$ Select target enchantment that player controls | TargetsWithDefinedController$ TriggeredTarget SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Enchantment | TgtPrompt$ Select target enchantment damaged player controls | TargetsWithDefinedController$ TriggeredTarget
DeckHas:Ability$Counters DeckHas:Ability$Counters
Oracle:Trample, protection from enchantments\n{4}{R}{G}: Monstrosity 3. (If this creature isn't monstrous, put three +1/+1 counters on it and it becomes monstrous.)\nWhenever Polis Crusher deals combat damage to a player, if Polis Crusher is monstrous, destroy target enchantment that player controls. Oracle:Trample, protection from enchantments\n{4}{R}{G}: Monstrosity 3. (If this creature isn't monstrous, put three +1/+1 counters on it and it becomes monstrous.)\nWhenever Polis Crusher deals combat damage to a player, if Polis Crusher is monstrous, destroy target enchantment that player controls.

View File

@@ -3,5 +3,5 @@ ManaCost:4 R R
Types:Creature Ogre Types:Creature Ogre
PT:5/4 PT:5/4
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigDestroy | CombatDamage$ True | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may destroy target artifact that player controls. T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigDestroy | CombatDamage$ True | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may destroy target artifact that player controls.
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select an artifact your opponent controls. SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredTarget | TgtPrompt$ Select target artifact damaged player controls
Oracle:Whenever Rustmouth Ogre deals combat damage to a player, you may destroy target artifact that player controls. Oracle:Whenever Rustmouth Ogre deals combat damage to a player, you may destroy target artifact that player controls.

View File

@@ -7,7 +7,7 @@ K:Trample
K:Haste K:Haste
K:etbCounter:P1P1:1:CheckSVar$ WasKicked:If CARDNAME was kicked, it enters the battlefield with a +1/+1 counter on it. K:etbCounter:P1P1:1:CheckSVar$ WasKicked:If CARDNAME was kicked, it enters the battlefield with a +1/+1 counter on it.
SVar:WasKicked:Count$Kicked.1.0 SVar:WasKicked:Count$Kicked.1.0
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | Execute$ TrigReturn | IsPresent$ Card.Self+counters_EQ0_P1P1 | TriggerDescription$ At the beginning of your end step, return Shatterskull Charger to its owner's hand unless it has a +1/+1 counter on it. T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | Execute$ TrigReturn | IsPresent$ Card.Self+counters_EQ0_P1P1 | TriggerDescription$ At the beginning of your end step, return CARDNAME to its owner's hand unless it has a +1/+1 counter on it.
SVar:TrigReturn:DB$ ChangeZone | Origin$ Battlefield | Destination$ Hand | Defined$ Self SVar:TrigReturn:DB$ ChangeZone | Origin$ Battlefield | Destination$ Hand | Defined$ Self
SVar:PlayMain1:TRUE SVar:PlayMain1:TRUE
DeckHas:Ability$Counters DeckHas:Ability$Counters

View File

@@ -4,5 +4,5 @@ Types:Creature Giant Shaman
PT:5/5 PT:5/5
S:Mode$ MinMaxBlocker | ValidCard$ Card.Self | Max$ 1 | Description$ CARDNAME can't be blocked by more than one creature. S:Mode$ MinMaxBlocker | ValidCard$ Card.Self | Max$ 1 | Description$ CARDNAME can't be blocked by more than one creature.
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigDestroy | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, destroy target artifact or enchantment that player controls. T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigDestroy | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, destroy target artifact or enchantment that player controls.
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredDefendingPlayer,Enchantment.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select target artifact or enchantment that player controls. SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredTarget,Enchantment.ControlledBy TriggeredTarget | TgtPrompt$ Select target artifact or enchantment damaged player controls
Oracle:Sunder Shaman can't be blocked by more than one creature.\nWhenever Sunder Shaman deals combat damage to a player, destroy target artifact or enchantment that player controls. Oracle:Sunder Shaman can't be blocked by more than one creature.\nWhenever Sunder Shaman deals combat damage to a player, destroy target artifact or enchantment that player controls.

View File

@@ -1,6 +1,6 @@
Name:Syndicate Recruiter Name:Syndicate Recruiter
ManaCost: 2 U B ManaCost: 2 U B
Types:Creature Vampire Assassin Types:Creature Vampire Rogue
PT:4/5 PT:4/5
K:Flying K:Flying
K:Ward:1 K:Ward:1

View File

@@ -4,6 +4,6 @@ Types:Creature Rat Ninja
PT:2/2 PT:2/2
K:Ninjutsu:2 B K:Ninjutsu:2 B
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigDestroy | CombatDamage$ True | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, destroy target nonblack creature that player controls. T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigDestroy | CombatDamage$ True | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, destroy target nonblack creature that player controls.
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Creature.nonBlack+ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select target nonblack creature defending player controls SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Creature.nonBlack+ControlledBy TriggeredTarget | TgtPrompt$ Select target nonblack creature damaged player controls
SVar:MustBeBlocked:True SVar:MustBeBlocked:True
Oracle:Ninjutsu {2}{B} ({2}{B}, Return an unblocked attacker you control to hand: Put this card onto the battlefield from your hand tapped and attacking.)\nWhenever Throat Slitter deals combat damage to a player, destroy target nonblack creature that player controls. Oracle:Ninjutsu {2}{B} ({2}{B}, Return an unblocked attacker you control to hand: Put this card onto the battlefield from your hand tapped and attacking.)\nWhenever Throat Slitter deals combat damage to a player, destroy target nonblack creature that player controls.

View File

@@ -4,5 +4,5 @@ Types:Creature Beast
PT:2/3 PT:2/3
K:Flying K:Flying
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | OptionalDecider$ You | CombatDamage$ True | Execute$ TrigDestroy | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may destroy target artifact or enchantment that player controls. T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | OptionalDecider$ You | CombatDamage$ True | Execute$ TrigDestroy | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may destroy target artifact or enchantment that player controls.
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredDefendingPlayer,Enchantment.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select target artifact or enchantment you don't control. SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredTarget,Enchantment.ControlledBy TriggeredTarget | TgtPrompt$ Select target artifact or enchantment damaged player controls
Oracle:Flying\nWhenever Trygon Predator deals combat damage to a player, you may destroy target artifact or enchantment that player controls. Oracle:Flying\nWhenever Trygon Predator deals combat damage to a player, you may destroy target artifact or enchantment that player controls.

View File

@@ -0,0 +1,6 @@
Name:And They Shall Know No Fear
ManaCost:1 W
Types:Instant
A:SP$ ChooseType | Type$ Creature | SubAbility$ DBPumpAll | AILogic$ MostProminentComputerControls | SpellDescription$ Choose a creature type.
SVar:DBPumpAll:DB$ PumpAll | ValidCards$ Creature.YouCtrl+ChosenType | NumAtt$ +1 | KW$ Indestructible | SpellDescription$ Creatures you control of the chosen type get +1/+0 and gain indestructible until end of turn.
Oracle:Choose a creature type. Creatures you control of the chosen type get +1/+0 and gain indestructible until end of turn.

View File

@@ -0,0 +1,10 @@
Name:Anrakyr the Traveller
ManaCost:4 B
Types:Legendary Artifact Creature Necron
PT:4/4
T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigCast | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME attacks, you may cast an artifact spell from your hand or graveyard by paying life equal to its mana value rather than paying its mana cost.
SVar:TrigCast:DB$ Play | ValidZone$ Hand | Valid$ Artifact.YouOwn | ValidSA$ Spell | Controller$ You | ValidZone$ Hand,Graveyard | Optional$ True | Amount$ 1 | PlayCost$ PayLife<ConvertedManaCost>
SVar:HasAttackEffect:TRUE
DeckHas:Ability$Graveyard
DeckHints:Type$Artifact
Oracle:Lord of the Pyrrhian Legions — Whenever Anrakyr the Traveller attacks, you may cast an artifact spell from your hand or graveyard by paying life equal to its mana value rather than paying its mana cost.

View File

@@ -0,0 +1,9 @@
Name:Assault Intercessor
ManaCost:1 W B
Types:Creature Astartes Warrior
PT:3/2
K:First strike
K:Menace
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.OppCtrl | TriggerZones$ Battlefield | Execute$ TrigLoseLife | TriggerDescription$ Chainsword — Whenever a creature an opponent controls dies, that player loses 2 life.
SVar:TrigLoseLife:DB$ LoseLife | LifeAmount$ 2 | Defined$ TriggeredCardController
Oracle:First strike, menace\nChainsword — Whenever a creature an opponent controls dies, that player loses 2 life.

View File

@@ -0,0 +1,10 @@
Name:Belisarius Cawl
ManaCost:2 W U
Types:Legendary Artifact Creature Human
PT:2/4
A:AB$ Token | PrecostDesc$ Ultima Founding — | Cost$ T tapXType<2/Artifact> | TokenScript$ w_2_2_astartes_warrior_vigilance | SpellDescription$ Create a 2/2 white Astartes Warrior creature token with vigilance.
A:AB$ Dig | PrecostDesc$ Master of Machines — | Cost$ T tapXType<X/Creature> | DigNum$ X | ChangeNum$ 1 | Optional$ True | ChangeValid$ Artifact | ForceRevealToController$ True | RestRandomOrder$ True | SpellDescription$ Look at the top X cards of your library. You may reveal an artifact card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.
SVar:X:Count$xPaid
DeckHas:Ability$Token & Type$Astartes|Warrior
DeckNeeds:Type$Artifact
Oracle:Ultima Founding — {T}, Tap two untapped artifacts you control: Create a 2/2 white Astartes Warrior creature token with vigilance.\nMaster of Machines — {T}, Tap X untapped creatures you control: Look at the top X cards of your library. You may reveal an artifact card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.

View File

@@ -0,0 +1,11 @@
Name:Birth of the Imperium
ManaCost:2 W U B
Types:Enchantment Saga
K:Saga:3:DBToken,DBSacrifice,DBDraw
SVar:DBToken:DB$ Token | TokenScript$ w_2_2_astartes_warrior_vigilance | TokenAmount$ X | SpellDescription$ Create a 2/2 white Astartes Warrior creature token with vigilance for each opponent you have.
SVar:X:PlayerCountOpponents$Amount
SVar:DBSacrifice:DB$ Sacrifice | Defined$ Opponent | SacValid$ Creature | SacMessage$ creature | SpellDescription$ Each opponent sacrifices a creature.
SVar:DBDraw:DB$ Draw | NumCards$ Y | NumCardsDesc$ two cards for each opponent who controls fewer creatures than you | SpellDescription$ Draw two cards for each opponent who controls fewer creatures than you.
SVar:Y:PlayerCountOpponents$HasPropertyhasFewerCreaturesInPlayThanYou/Times.2
DeckHas:Ability$Token & Type$Astartes|Warrior
Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)\nI — Create a 2/2 white Astartes Warrior creature token with vigilance for each opponent you have.\nII — Each opponent sacrifices a creature.\nIII — Draw two cards for each opponent who controls fewer creatures than you.

View File

@@ -0,0 +1,9 @@
Name:Chaos Terminator Lord
ManaCost:3 R
Types:Creature Astartes Warrior
PT:3/3
T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | Execute$ TrigPump | TriggerZones$ Battlefield | TriggerDescription$ Lord of Chaos — At the beginning of combat on your turn, another target creature you control gains double strike until end of turn.
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature.Other+YouCtrl | TgtPrompt$ Select another target creature you control | KW$ Double Strike
SVar:PlayMain1:TRUE
DeckHas:Keyword$DoubleStrike
Oracle:Lord of Chaos — At the beginning of combat on your turn, another target creature you control gains double strike until end of turn.

View File

@@ -0,0 +1,10 @@
Name:Chronomancer
ManaCost:1 B
Types:Artifact Creature Necron Wizard
PT:1/1
K:Flying
A:AB$ Draw | PrecostDesc$ Atomic Transmutation — | Cost$ 1 T Sac<1/Artifact.Other/another artifact> | SpellDescription$ Draw a card.
K:Unearth:2 B
DeckHas:Ability$Sacrifice|Graveyard
DeckHints:Type$Artifact
Oracle:Flying\nAtomic Transmutation — {1}, {T}, Sacrifice another artifact: Draw a card.\nUnearth {2}{B} ({2}{B}: Return this card from your graveyard to the battlefield. It gains haste. Exile it at the beginning of the next end step or if it would leave the battlefield. Unearth only as a sorcery.)

View File

@@ -0,0 +1,7 @@
Name:Cryptic Spires
ManaCost:no cost
Types:Land
Text:As you create your deck, circle two of the colors below.
K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ Combo Chosen | SpellDescription$ Add mana of either of the circled colors.
Oracle:As you create your deck, circle two of the colors below.\nCryptic Spires enters the battlefield tapped.\n{T}: Add one mana of either of the circled colors.

View File

@@ -0,0 +1,6 @@
Name:Exterminatus
ManaCost:5 W B
Types:Sorcery
A:SP$ AnimateAll | ValidCards$ Permanent.nonLand+OppCtrl | RemoveKeywords$ Indestructible | SubAbility$ DBDestroyAll | SpellDescription$ Nonland permanents your opponents control lose indestructible until end of turn. Destroy all nonland permanents.
SVar:DBDestroyAll:DB$ DestroyAll | ValidCards$ Permanent.nonLand
Oracle:Nonland permanents your opponents control lose indestructible until end of turn.\nDestroy all nonland permanents.

View File

@@ -0,0 +1,11 @@
Name:Grey Knight Paragon
ManaCost:4 W
Types:Creature Astartes Knight
PT:4/4
K:Flash
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigBranch | TriggerDescription$ Rites of Banishment — When CARDNAME enters the battlefield, destroy target attacking creature. If that creature is a Demon, exile it instead.
SVar:TrigBranch:DB$ Branch | ValidTgts$ Creature.attacking | TgtPrompt$ Select target attacking creature | BranchConditionSVar$ X | BranchConditionSVarCompare$ EQ1 | TrueSubAbility$ ExileDemon | FalseSubAbility$ DestroyAttacker
SVar:DestroyAttacker:DB$ Destroy | Defined$ Targeted
SVar:ExileDemon:DB$ ChangeZone | Defined$ Targeted | Origin$ Battlefield | Destination$ Exile
SVar:X:Targeted$Valid Creature.Demon
Oracle:Flash\nRites of Banishment — When Grey Knight Paragon enters the battlefield, destroy target attacking creature. If that creature is a Demon, exile it instead.

View File

@@ -0,0 +1,8 @@
Name:Helbrute
ManaCost:3 B R
Types:Artifact Creature Astartes Dreadnought
PT:5/4
K:Haste
SVar:AltCost:Cost$ 3 B R ExileFromGrave<1/Creature.Other/another creature card> | PrecostDesc$ Sarcophagus — | ActivationZone$ Graveyard | Description$ You may cast CARDNAME from your graveyard by exiling another creature card from your graveyard in addition to paying its other costs.
DeckHas:Ability$Graveyard
Oracle:Haste\nSarcophagus — You may cast Helbrute from your graveyard by exiling another creature card from your graveyard in addition to paying its other costs.

View File

@@ -0,0 +1,9 @@
Name:Lord of Change
ManaCost:6 U
Types:Creature Demon
PT:6/6
K:Flying
K:Ward:3
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDraw | TriggerDescription$ Architect of Deception — When CARDNAME enters the battlefield, draw three cards.
SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 3
Oracle:Flying, ward {3}\nArchitect of Deception — When Lord of Change enters the battlefield, draw three cards.

View File

@@ -0,0 +1,10 @@
Name:Necron Deathmark
ManaCost:3 B B
Types:Artifact Creature Necron
PT:5/3
K:Flash
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDestroy | TriggerDescription$ Synaptic Disintegrator — When CARDNAME enters the battlefield, destroy up to one target creature and target player mills three cards.
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Creature | TgtPrompt$ Select up to one target creature | TargetMin$ 0 | TargetMax$ 1 | SubAbility$ DBMill
SVar:DBMill:DB$ Mill | ValidTgts$ Player | NumCards$ 3
DeckHas:Ability$Mill
Oracle:Flash\nSynaptic Disintegrator — When Necron Deathmark enters the battlefield, destroy up to one target creature and target player mills three cards.

View File

@@ -0,0 +1,15 @@
Name:Necron Monolith
ManaCost:7
Types:Artifact Vehicle
PT:7/7
K:Flying
K:Indestructible
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigMill | TriggerDescription$ Eternity Gate — Whenever CARDNAME attacks, mill three cards. For each creature card milled this way, create a 2/2 black Necron Warrior artifact creature token.
SVar:TrigMill:DB$ Mill | NumCards$ 3 | RememberMilled$ True | SubAbility$ DBToken
SVar:DBToken:DB$ Token | TokenAmount$ X | TokenScript$ b_2_2_a_necron_warrior | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
K:Crew:4
SVar:X:Remembered$Valid Creature
DeckHas:Ability$Mill|Token & Type$Necron|Warrior
SVar:HasAttackEffect:TRUE
Oracle:Flying, indestructible\nEternity Gate — Whenever Necron Monolith attacks, mill three cards. For each creature card milled this way, create a 2/2 black Necron Warrior artifact creature token.\nCrew 4 (Tap any number of creatures you control with total power 4 or more: This Vehicle becomes an artifact creature until end of turn.)

View File

@@ -0,0 +1,8 @@
Name:Necron Overlord
ManaCost:2 B B
Types:Artifact Creature Necron Noble
PT:2/5
A:AB$ LoseLife | PrecostDesc$ Relentless Mind — | Cost$ X T tapXType<X/Artifact> | ValidTgts$ Opponent | LifeAmount$ X | SpellDescription$ Target opponent loses X life.
SVar:X:Count$xPaid
DeckHints:Type$Artifact
Oracle:Relentless Mind — {X}, {T}, Tap X untapped artifacts you control: Target opponent loses X life.

View File

@@ -0,0 +1,10 @@
Name:Night Scythe
ManaCost:3
Types:Artifact Vehicle
PT:3/1
K:Flying
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ Invasion Beams — When CARDNAME enters the battlefield, create a 2/2 black Necron Warrior artifact creature token.
SVar:TrigToken:DB$ Token | TokenScript$ b_2_2_a_necron_warrior
K:Crew:2
DeckHas:Type$Necron|Warrior & Ability$Token
Oracle:Flying\nInvasion Beams — When Night Scythe enters the battlefield, create a 2/2 black Necron Warrior artifact creature token.\nCrew 2 (Tap any number of creatures you control with total power 2 or more: This Vehicle becomes an artifact creature until end of turn.)

View File

@@ -0,0 +1,80 @@
Name:Shadowheart, Sharran Cleric
ManaCost:1 B
Types:Legendary Creature Human Elf Cleric
PT:2/2
K:Deathtouch
K:Specialize:2::Activate only if a player has 13 or less life.:CheckSVar$ X | SVarCompare$ LE13
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigDealDamage | TriggerDescription$ At the beginning of your end step, CARDNAME deals 1 damage to each player.
SVar:TrigDealDamage:DB$ DealDamage | Defined$ Player | NumDmg$ 1
SVar:X:PlayerCountPlayers$LowestLifeTotal
AlternateMode:Specialize
DeckHas:Ability$Discard
Oracle:Deathtouch\nSpecialize {2}. Activate only if a player has 13 or less life.\nAt the beginning of your end step, Shadowheart, Sharran Cleric deals 1 damage to each player.
SPECIALIZE:WHITE
Name:Shadowheart, Cleric of Order
ManaCost:1 W B
Types:Legendary Creature Human Elf Cleric
PT:4/4
K:Deathtouch
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigDealDamage | TriggerDescription$ At the beginning of your end step, CARDNAME deals 1 damage to each player.
SVar:TrigDealDamage:DB$ DealDamage | Defined$ Player | NumDmg$ 1
T:Mode$ LifeLost | ValidPlayer$ You | TriggerZones$ Battlefield | PlayerTurn$ True | Execute$ TrigToken | TriggerDescription$ Whenever you lose life during your turn, create a 2/2 white Knight creature token.
SVar:TrigToken:DB$ Token | TokenScript$ w_2_2_knight
DeckHas:Ability$Token & Type$Knight
Oracle:Deathtouch\nAt the beginning of your end step, Shadowheart, Cleric of Order deals 1 damage to each player.\nWhenever you lose life during your turn, create a 2/2 white Knight creature token.
SPECIALIZE:BLUE
Name:Shadowheart, Cleric of Trickery
ManaCost:1 U B
Types:Legendary Creature Human Elf Cleric
PT:4/4
K:Deathtouch
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigDealDamage | TriggerDescription$ At the beginning of your end step, CARDNAME deals 1 damage to each player.
SVar:TrigDealDamage:DB$ DealDamage | Defined$ Player | NumDmg$ 1
T:Mode$ LifeLost | ValidPlayer$ You | TriggerZones$ Battlefield | PlayerTurn$ True | Execute$ TrigDraw | TriggerDescription$ Whenever you lose life during your turn, draw a card.
SVar:TrigDraw:DB$ Draw
Oracle:Deathtouch\nAt the beginning of your end step, Shadowheart, Cleric of Trickery deals 1 damage to each player.\nWhenever you lose life during your turn, draw a card.
SPECIALIZE:BLACK
Name:Shadowheart, Cleric of Graves
ManaCost:1 B B
Types:Legendary Creature Human Elf Cleric
PT:4/4
K:Deathtouch
K:Lifelink
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigDealDamage | TriggerDescription$ At the beginning of your end step, CARDNAME deals 1 damage to each player.
SVar:TrigDealDamage:DB$ DealDamage | Defined$ Player | NumDmg$ 1
DeckHas:Ability$LifeGain
Oracle:Deathtouch, lifelink\nAt the beginning of your end step, Shadowheart, Cleric of Graves deals 1 damage to each player.
SPECIALIZE:RED
Name:Shadowheart, Cleric of War
ManaCost:1 B R
Types:Legendary Creature Human Elf Cleric
PT:4/4
K:Deathtouch
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigDamageAll | TriggerDescription$ At the beginning of your end step, CARDNAME deals 1 damage to each player.
SVar:TrigDamageAll:DB$ DealDamage | Defined$ Player | NumDmg$ 1
T:Mode$ LifeLost | ValidPlayer$ You | TriggerZones$ Battlefield | PlayerTurn$ True | Execute$ TrigDamageOpp | TriggerDescription$ Whenever you lose life during your turn, NICKNAME deals that much damage to each opponent.
SVar:TrigDamageOpp:DB$ DealDamage | NumDmg$ X | Defined$ Opponent
SVar:X:TriggerCount$LifeAmount
Oracle:Deathtouch\nAt the beginning of your end step, Shadowheart, Cleric of War deals 1 damage to each player.\nWhenever you lose life during your turn, Shadowheart deals that much damage to each opponent.
SPECIALIZE:GREEN
Name:Shadowheart, Cleric of Twilight
ManaCost:1 B G
Types:Legendary Creature Human Elf Cleric
PT:4/4
K:Deathtouch
S:Mode$ CantBlockBy | ValidAttacker$ Creature.Self | ValidBlocker$ Creature.powerLE2 | Description$ CARDNAME can't be blocked by creatures with power 2 or less.
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigDealDamage | TriggerDescription$ At the beginning of your end step, NICKNAME deals 1 damage to each player.
SVar:TrigDealDamage:DB$ DealDamage | Defined$ Player | NumDmg$ 1
T:Mode$ LifeLost | ValidPlayer$ You | TriggerZones$ Battlefield | PlayerTurn$ True | Execute$ TrigPutCounter | TriggerDescription$ Whenever you lose life during your turn, put a +1/+1 counter on NICKNAME.
SVar:TrigPutCounter:DB$ PutCounter | CounterType$ P1P1
Oracle:Deathtouch\nShadowheart, Cleric of Twilight can't be blocked by creatures with power 2 or less.\nAt the beginning of your end step, Shadowheart deals 1 damage to each player.\nWhenever you lose life during your turn, put a +1/+1 counter on Shadowheart.

View File

@@ -0,0 +1,10 @@
Name:Sister Hospitaller
ManaCost:4 W B
Types:Creature Human Cleric
PT:3/2
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChangeZone | TriggerDescription$ Medicus Ministorum - When CARDNAME enters the battlefield, return target creature card from your graveyard to the battlefield. You gain life equal to that card's mana value.
SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Creature.YouOwn | TgtPrompt$ Choose target creature card in your graveyard | ChangeNum$ 1 | SubAbility$ DBGainLife
SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ X
SVar:X:Targeted$CardManaCost
DeckHas:Ability$Graveyard|Lifegain
Oracle:Medicus Ministorum — When Sister Hospitaller enters the battlefield, return target creature card from your graveyard to the battlefield. You gain life equal to its mana value.

View File

@@ -0,0 +1,9 @@
Name:Thunderwolf Cavalry
ManaCost:4 W
Types:Creature Astartes Warrior
PT:4/4
K:First Strike
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigPutCounter | CombatDamage$ True | TriggerDescription$ Crushing Teeth — Whenever CARDNAME deals combat damage to a player, put a +1/+1 counter on each other creature you control.
SVar:TrigPutCounter:DB$ PutCounterAll | ValidCards$ Creature.YouCtrl+Other | CounterType$ P1P1 | CounterNum$ 1
DeckHas:Ability$Counters
Oracle:First strike\nCrushing Teeth — Whenever Thunderwolf Cavalry deals combat damage to a player, put a +1/+1 counter on each other creature you control.

View File

@@ -0,0 +1,12 @@
Name:Tomb Blade
ManaCost:4 B B
Types:Artifact Creature Necron
PT:5/4
K:Flying
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigLoseLife | CombatDamage$ True | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, that player loses life equal to the number of creatures they control unless they sacrifice a creature.
SVar:TrigLoseLife:DB$ LoseLife | Defined$ TriggeredTarget | UnlessCost$ Sac<1/Creature> | UnlessPayer$ TriggeredTarget | LifeAmount$ X
SVar:X:TriggeredTarget$Valid Creature.YouCtrl
K:Unearth:6 B B
DeckHas:Ability$Sacrifice|Graveyard
SVar:HasAttackEffect:TRUE
Oracle:Flying\nWhenever Tomb Blade deals combat damage to a player, that player loses life equal to the number of creatures they control unless they sacrifice a creature.\nUnearth {6}{B}{B}

View File

@@ -0,0 +1,9 @@
Name:Tomb Fortress
ManaCost:no cost
Types:Land
K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ B | SpellDescription$ Add {B}.
A:AB$ Mill | Cost$ 2 B B B T Exile<1/CARDNAME> | Defined$ You | SorcerySpeed$ True | NumCards$ 4 | SubAbility$ DBReturn | SpellDescription$ Mill four cards, then return a creature card from your graveyard to the battlefield. Activate only as a sorcery.
SVar:DBReturn:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.YouOwn | ChangeNum$ 1 | Hidden$ True
DeckHas:Ability$Graveyard|Mill
Oracle:Tomb Fortress enters the battlefield tapped.\n{T}: Add {B}.\n{2}{B}{B}{B}, {T}, Exile Tomb Fortress: Mill four cards, then return a creature card from your graveyard to the battlefield. Activate only as a sorcery.

View File

@@ -0,0 +1,7 @@
Name:Trazyn the Infinite
ManaCost:4 B B
Types:Legendary Artifact Creature Necron
PT:4/6
S:Mode$ Continuous | Affected$ Card.Self | EffectZone$ Battlefield | GainsAbilitiesOf$ Artifact.YouOwn | GainsAbilitiesOfZones$ Graveyard | Description$ As long as Trazyn the Infinite is on the battlefield, it has all activated abilities of all artifact cards in your graveyard.
DeckHints:Type$Artifact & Ability$Graveyard
Oracle:As long as Trazyn the Infinite is on the battlefield, it has all activated abilities of all artifact cards in your graveyard.

View File

@@ -0,0 +1,11 @@
Name:Triarch Praetorian
ManaCost:1 B
Types:Artifact Creature Necron
PT:2/1
K:Flying
T:Mode$ ChangesZone | Origin$ Graveyard | Destination$ Battlefield | TriggerZones$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDraw | TriggerDescription$ Dynastic Codes — When CARDNAME enters the battlefield from a graveyard, you draw two cards and you lose 2 life.
SVar:TrigDraw:DB$ Draw | NumCards$ 2 | SubAbility$ DBLoseLife
SVar:DBLoseLife:DB$ LoseLife | LifeAmount$ 2
K:Unearth:4 B
DeckHas:Ability$Graveyard
Oracle:Flying\nDynastic Codes — When Triarch Praetorian enters the battlefield from a graveyard, you draw two cards and you lose 2 life.\nUnearth {4}{B} ({4}{B}: Return this card from your graveyard to the battlefield. It gains haste. Exile it at the beginning of the next end step or if it would leave the battlefield. Unearth only as a sorcery.)

View File

@@ -0,0 +1,9 @@
Name:Triarch Stalker
ManaCost:3 B B
Types:Artifact Creature Necron
PT:4/5
S:Mode$ Continuous | Affected$ Creature.attacking ChosenPlayer | AddKeyword$ Menace | Description$ Creatures attacking the last chosen player have menace.
T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | Execute$ TrigChoose | TriggerZones$ Battlefield | TriggerDescriptionLure the Unwary — At the beginning of combat on your turn, choose an opponent.
SVar:TrigChoose:DB$ ChoosePlayer | Defined$ You | Choices$ Player.Opponent
DeckHas:Keyword$Menace
Oracle:Targeting Relay — At the beginning of combat on your turn, choose an opponent.\nCreatures attacking the last chosen player have menace.

View File

@@ -0,0 +1,12 @@
Name:Trygon Prime
ManaCost:2 G U
Types:Creature Tyranid
PT:4/4
K:Vigilance
T:Mode$ Attacks | ValidCard$ Creature.Self | Execute$ TrigCounters | TriggerDescription$ Subterranean Assault — Whenever cardname attacks, put a +1/+1 counter on it and a +1/+1 counter on up to one other target attacking creature. That creature can't be blocked this turn.
SVar:TrigCounters:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBCounter
SVar:DBCounter:DB$ PutCounter | ValidTgts$ Creature.attacking+Other | TargetMin$ 0 | TargetMax$ 1 | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBPump
SVar:DBPump:DB$ Pump | Defined$ ParentTarget | KW$ HIDDEN Unblockable
DeckHas:Ability$Counters
SVar:HasAttackEffect:TRUE
Oracle:Subterranean Assault — Whenever Trygon Prime attacks, put a +1/+1 counter on it and a +1/+1 counter on up to one other target attacking creature. That creature can't be blocked this turn.

View File

@@ -0,0 +1,10 @@
Name:Tyranid Harridan
ManaCost:4 G U
Types:Creature Tyranid
K:Flying
K:Ward:4
PT:4/4
T:Mode$ DamageDone | ValidSource$ Card.Self,Tyranid.YouCtrl | ValidTarget$ Player | CombatDamage$ True | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Shrieking Gargoyles — Whenever CARDNAME or another Tyranid you control deals combat damage to a player, create a 1/1 blue Tyranid Gargoyle creature token with flying.
SVar:TrigToken:DB$ Token | TokenScript$ u_1_1_tyranid_gargoyle_flying
DeckHas:Type$Gargoyle & Ability$Token
Oracle:Flying, ward {4}\nShrieking Gargoyles — Whenever Tyranid Harridan or another Tyranid you control deals combat damage to a player, create a 1/1 blue Tyranid Gargoyle creature token with flying.

View File

@@ -0,0 +1,10 @@
Name:Tzaangor Shaman
ManaCost:2 U R
Types:Creature Mutant Shaman
PT:3/3
K:Flying
T:Mode$ DamageDone | CombatDamage$ True | ValidTarget$ Player | ValidSource$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigDelayedTrigger | TriggerDescription$ Sorcerous Elixir — Whenever CARDNAME deals combat damage to a player, copy the next instant or sorcery spell you cast this turn when you cast it. You may choose new targets for the copy.
SVar:TrigDelayedTrigger:DB$ DelayedTrigger | AILogic$ SpellCopy | Execute$ EffTrigCopy | ThisTurn$ True | Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | SpellDescription$ When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.
SVar:EffTrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
DeckHints:Type$Instant|Sorcery
Oracle:Flying\nSorcerous Elixir — Whenever Tzaangor Shaman deals combat damage to a player, copy the next instant or sorcery spell you cast this turn when you cast it. You may choose new targets for the copy.

View File

@@ -0,0 +1,9 @@
Name:Venomcrawler
ManaCost:3 B
Types:Artifact Creature Demon
PT:2/2
K:Lifelink
T:Mode$ ChangesZone | Origin$ Battlefield | ValidCard$ Creature.Other | Destination$ Graveyard | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Devourer of Souls — Whenever another creature dies, put a +1/+1 counter on CARDNAME.
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
DeckHas:Ability$Counters
Oracle:Lifelink\nDevourer of Souls — Whenever another creature dies, put a +1/+1 counter on Venomcrawler.

View File

@@ -0,0 +1,8 @@
Name:Venomthrope
ManaCost:1 G U
Types:Creature Tyranid
PT:2/2
K:Flying
K:Deathtouch
K:Hexproof
Oracle:Flying, deathtouch, hexproof

View File

@@ -0,0 +1,10 @@
Name:Vexilus Praetor
ManaCost:3 W
Types:Creature Custodes Warrior
PT:3/4
K:Flash
K:Vilance
S:Mode$ Continuous | Affected$ Card.IsCommander+YouCtrl | AddKeyword$ Protection from everything | Description$ Aegis of the Emperor — Commanders you control have protection from everything.
SVar:PlayMain1:TRUE
AI:RemoveDeck:Random
Oracle:Flash\nVigilance\nAegis of the Emperor — Commanders you control have protection from everything.

View File

@@ -46,14 +46,14 @@ public class GuiDownloadPicturesHQ extends GuiDownloadService {
existingSets = retrieveManifestDirectory(); existingSets = retrieveManifestDirectory();
for (final PaperCard c : FModel.getMagicDb().getCommonCards().getAllCards()) { for (final PaperCard c : FModel.getMagicDb().getCommonCards().getAllCards()) {
addDLObject(c, false); addDLObject(c, "");
if (c.hasBackFace()) { if (c.hasBackFace()) {
addDLObject(c, true); addDLObject(c, "back");
} }
} }
for (final PaperCard c : FModel.getMagicDb().getVariantCards().getAllCards()) { for (final PaperCard c : FModel.getMagicDb().getVariantCards().getAllCards()) {
addDLObject(c, false); addDLObject(c, "");
} }
// Add missing tokens to the list of things to download. // Add missing tokens to the list of things to download.
@@ -62,8 +62,8 @@ public class GuiDownloadPicturesHQ extends GuiDownloadService {
return downloads; return downloads;
} }
private void addDLObject(final PaperCard c, final boolean backFace) { private void addDLObject(final PaperCard c, final String face) {
final String imageKey = ImageUtil.getImageKey(c, backFace, false); final String imageKey = ImageUtil.getImageKey(c, face, false);
final String destPath = ForgeConstants.CACHE_CARD_PICS_DIR + imageKey + ".jpg"; final String destPath = ForgeConstants.CACHE_CARD_PICS_DIR + imageKey + ".jpg";
if (existingImages.contains(imageKey + ".jpg")) { if (existingImages.contains(imageKey + ".jpg")) {
@@ -98,7 +98,7 @@ public class GuiDownloadPicturesHQ extends GuiDownloadService {
cardname = cardname.replace("'", ""); cardname = cardname.replace("'", "");
String scryfallurl = ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD + "named?fuzzy=" + cardname; String scryfallurl = ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD + "named?fuzzy=" + cardname;
if(!setCode.equals("???")) scryfallurl += "&set=" + setCode.toLowerCase(); if(!setCode.equals("???")) scryfallurl += "&set=" + setCode.toLowerCase();
if(backFace) scryfallurl += "&face=back"; if(face.equals("back")) scryfallurl += "&face=back";
scryfallurl += "&format=image"; scryfallurl += "&format=image";
downloads.put(destPath, scryfallurl); downloads.put(destPath, scryfallurl);

View File

@@ -40,14 +40,14 @@ public class GuiDownloadPicturesLQ extends GuiDownloadService {
existingSets = retrieveManifestDirectory(); existingSets = retrieveManifestDirectory();
for (final PaperCard c : FModel.getMagicDb().getCommonCards().getAllCards()) { for (final PaperCard c : FModel.getMagicDb().getCommonCards().getAllCards()) {
addDLObject(c, false); addDLObject(c, "");
if (c.hasBackFace()) { if (c.hasBackFace()) {
addDLObject(c, true); addDLObject(c, "back");
} }
} }
for (final PaperCard c : FModel.getMagicDb().getVariantCards().getAllCards()) { for (final PaperCard c : FModel.getMagicDb().getVariantCards().getAllCards()) {
addDLObject(c, false); addDLObject(c, "");
} }
// Add missing tokens to the list of things to download. // Add missing tokens to the list of things to download.
@@ -56,8 +56,8 @@ public class GuiDownloadPicturesLQ extends GuiDownloadService {
return downloads; return downloads;
} }
private void addDLObject(final PaperCard c, final boolean backFace) { private void addDLObject(final PaperCard c, final String face) {
final String imageKey = ImageUtil.getImageKey(c, backFace, false); final String imageKey = ImageUtil.getImageKey(c, face, false);
final String destPath = ForgeConstants.CACHE_CARD_PICS_DIR + imageKey + ".jpg"; final String destPath = ForgeConstants.CACHE_CARD_PICS_DIR + imageKey + ".jpg";
if (ImageKeys.getImageFile(imageKey) != null) { if (ImageKeys.getImageFile(imageKey) != null) {
@@ -76,6 +76,6 @@ public class GuiDownloadPicturesLQ extends GuiDownloadService {
return; return;
} }
downloads.put(destPath, ForgeConstants.URL_PIC_DOWNLOAD + ImageUtil.getDownloadUrl(c, backFace)); downloads.put(destPath, ForgeConstants.URL_PIC_DOWNLOAD + ImageUtil.getDownloadUrl(c, face));
} }
} }

View File

@@ -72,10 +72,10 @@ public class GuiDownloadSetPicturesLQ extends GuiDownloadService {
continue; continue;
} }
addDLObject(ImageUtil.getDownloadUrl(c, false), ImageUtil.getImageKey(c, false, true), downloads); addDLObject(ImageUtil.getDownloadUrl(c, ""), ImageUtil.getImageKey(c, "", true), downloads);
if (c.hasBackFace()) { if (c.hasBackFace()) {
addDLObject(ImageUtil.getDownloadUrl(c, true), ImageUtil.getImageKey(c, true, true), downloads); addDLObject(ImageUtil.getDownloadUrl(c, "back"), ImageUtil.getImageKey(c, "back", true), downloads);
} }
} }

View File

@@ -39,7 +39,7 @@ public abstract class ImageFetcher {
private HashMap<String, HashSet<Callback>> currentFetches = new HashMap<>(); private HashMap<String, HashSet<Callback>> currentFetches = new HashMap<>();
private HashMap<String, String> tokenImages; private HashMap<String, String> tokenImages;
private String getScryfallDownloadURL(PaperCard c, boolean backFace, boolean useArtCrop, boolean hasSetLookup, String imagePath, ArrayList<String> downloadUrls) { private String getScryfallDownloadURL(PaperCard c, String face, boolean useArtCrop, boolean hasSetLookup, String imagePath, ArrayList<String> downloadUrls) {
StaticData data = StaticData.instance(); StaticData data = StaticData.instance();
CardEdition edition = data.getEditions().get(c.getEdition()); CardEdition edition = data.getEditions().get(c.getEdition());
if (edition == null) // edition does not exist - some error occurred with card data if (edition == null) // edition does not exist - some error occurred with card data
@@ -53,7 +53,7 @@ public abstract class ImageFetcher {
if (ed != null) { if (ed != null) {
String setCode =ed.getScryfallCode(); String setCode =ed.getScryfallCode();
String langCode = ed.getCardsLangCode(); String langCode = ed.getCardsLangCode();
downloadUrls.add(ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD + ImageUtil.getScryfallDownloadUrl(pc, backFace, setCode, langCode, useArtCrop)); downloadUrls.add(ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD + ImageUtil.getScryfallDownloadUrl(pc, face, setCode, langCode, useArtCrop));
} }
} }
} else {// original from set } else {// original from set
@@ -61,7 +61,7 @@ public abstract class ImageFetcher {
if (ed != null) { if (ed != null) {
String setCode =ed.getScryfallCode(); String setCode =ed.getScryfallCode();
String langCode = ed.getCardsLangCode(); String langCode = ed.getCardsLangCode();
downloadUrls.add(ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD + ImageUtil.getScryfallDownloadUrl(pc, backFace, setCode, langCode, useArtCrop)); downloadUrls.add(ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD + ImageUtil.getScryfallDownloadUrl(pc, face, setCode, langCode, useArtCrop));
} }
} }
} }
@@ -71,7 +71,7 @@ public abstract class ImageFetcher {
String setCode = edition.getScryfallCode(); String setCode = edition.getScryfallCode();
String langCode = edition.getCardsLangCode(); String langCode = edition.getCardsLangCode();
return ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD + return ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD +
ImageUtil.getScryfallDownloadUrl(c, backFace, setCode, langCode, useArtCrop); ImageUtil.getScryfallDownloadUrl(c, face, setCode, langCode, useArtCrop);
} }
} }
@@ -105,10 +105,46 @@ public abstract class ImageFetcher {
// Skip fetching if artist info is not available for art crop // Skip fetching if artist info is not available for art crop
if (useArtCrop && paperCard.getArtist().isEmpty()) if (useArtCrop && paperCard.getArtist().isEmpty())
return; return;
String imagePath = ImageUtil.getImageRelativePath(paperCard, false, true, false); String imagePath = ImageUtil.getImageRelativePath(paperCard, "", true, false);
final boolean hasSetLookup = ImageKeys.hasSetLookup(imagePath); final boolean hasSetLookup = ImageKeys.hasSetLookup(imagePath);
final boolean backFace = imageKey.endsWith(ImageKeys.BACKFACE_POSTFIX); String face = "";
String filename = backFace ? paperCard.getCardAltImageKey() : paperCard.getCardImageKey(); if (imageKey.endsWith(ImageKeys.BACKFACE_POSTFIX)) {
face = "back";
} else if (imageKey.endsWith(ImageKeys.SPECFACE_W)) {
face = "white";
} else if (imageKey.endsWith(ImageKeys.SPECFACE_U)) {
face = "blue";
} else if (imageKey.endsWith(ImageKeys.SPECFACE_B)) {
face = "black";
} else if (imageKey.endsWith(ImageKeys.SPECFACE_R)) {
face = "red";
} else if (imageKey.endsWith(ImageKeys.SPECFACE_G)) {
face = "green";
}
String filename = "";
switch (face) {
case "back":
filename = paperCard.getCardAltImageKey();
break;
case "white":
filename = paperCard.getCardWSpecImageKey();
break;
case "blue":
filename = paperCard.getCardUSpecImageKey();
break;
case "black":
filename = paperCard.getCardBSpecImageKey();
break;
case "red":
filename = paperCard.getCardRSpecImageKey();
break;
case "green":
filename = paperCard.getCardGSpecImageKey();
break;
default:
filename = paperCard.getCardImageKey();
break;
}
if (useArtCrop) { if (useArtCrop) {
filename = TextUtil.fastReplace(filename, ".full", ".artcrop"); filename = TextUtil.fastReplace(filename, ".full", ".artcrop");
} }
@@ -119,7 +155,7 @@ public abstract class ImageFetcher {
//move priority of ftp image here //move priority of ftp image here
StringBuilder setDownload = new StringBuilder(ForgeConstants.URL_PIC_DOWNLOAD); StringBuilder setDownload = new StringBuilder(ForgeConstants.URL_PIC_DOWNLOAD);
if (!hasSetLookup) { if (!hasSetLookup) {
setDownload.append(ImageUtil.getDownloadUrl(paperCard, backFace)); setDownload.append(ImageUtil.getDownloadUrl(paperCard, face));
downloadUrls.add(setDownload.toString()); downloadUrls.add(setDownload.toString());
} else { } else {
List<PaperCard> clones = StaticData.instance().getCommonCards().getAllCards(paperCard.getName()); List<PaperCard> clones = StaticData.instance().getCommonCards().getAllCards(paperCard.getName());
@@ -127,12 +163,12 @@ public abstract class ImageFetcher {
if (clones.size() > 1) {//clones only if (clones.size() > 1) {//clones only
if (!paperCard.getEdition().equalsIgnoreCase(pc.getEdition())) { if (!paperCard.getEdition().equalsIgnoreCase(pc.getEdition())) {
StringBuilder set = new StringBuilder(ForgeConstants.URL_PIC_DOWNLOAD); StringBuilder set = new StringBuilder(ForgeConstants.URL_PIC_DOWNLOAD);
set.append(ImageUtil.getDownloadUrl(pc, backFace)); set.append(ImageUtil.getDownloadUrl(pc, face));
downloadUrls.add(set.toString()); downloadUrls.add(set.toString());
} }
} else {// original from set } else {// original from set
StringBuilder set = new StringBuilder(ForgeConstants.URL_PIC_DOWNLOAD); StringBuilder set = new StringBuilder(ForgeConstants.URL_PIC_DOWNLOAD);
set.append(ImageUtil.getDownloadUrl(pc, backFace)); set.append(ImageUtil.getDownloadUrl(pc, face));
downloadUrls.add(set.toString()); downloadUrls.add(set.toString());
} }
} }
@@ -140,7 +176,7 @@ public abstract class ImageFetcher {
} }
final String cardCollectorNumber = paperCard.getCollectorNumber(); final String cardCollectorNumber = paperCard.getCollectorNumber();
if (!cardCollectorNumber.equals(IPaperCard.NO_COLLECTOR_NUMBER)) { if (!cardCollectorNumber.equals(IPaperCard.NO_COLLECTOR_NUMBER)) {
final String scryfallURL = this.getScryfallDownloadURL(paperCard, backFace, useArtCrop, hasSetLookup, imagePath, downloadUrls); final String scryfallURL = this.getScryfallDownloadURL(paperCard, face, useArtCrop, hasSetLookup, filename, downloadUrls);
if (scryfallURL != null && !hasSetLookup) if (scryfallURL != null && !hasSetLookup)
downloadUrls.add(scryfallURL); downloadUrls.add(scryfallURL);
} }