Merge branch 'master' of git.cardforge.org:core-developers/forge into agetian-master

This commit is contained in:
Michael Kamensky
2021-11-19 21:29:13 +03:00
481 changed files with 1519 additions and 660 deletions

View File

@@ -11,5 +11,6 @@ public class DifficultyData {
public int staringMoney=10; public int staringMoney=10;
public float enemyLifeFactor=1; public float enemyLifeFactor=1;
public boolean startingDifficulty; public boolean startingDifficulty;
public float sellFactor=0.2f;
} }

View File

@@ -0,0 +1,805 @@
package forge.adventure.scene;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Align;
import com.google.common.base.Function;
import forge.Forge;
import forge.Graphics;
import forge.adventure.AdventureApplicationAdapter;
import forge.adventure.world.AdventurePlayer;
import forge.assets.FImage;
import forge.assets.FSkinFont;
import forge.assets.FSkinImage;
import forge.deck.*;
import forge.gui.FThreads;
import forge.item.InventoryItem;
import forge.item.PaperCard;
import forge.itemmanager.*;
import forge.itemmanager.filters.ItemFilter;
import forge.localinstance.properties.ForgePreferences;
import forge.menu.FCheckBoxMenuItem;
import forge.menu.FDropDownMenu;
import forge.menu.FMenuItem;
import forge.menu.FPopupMenu;
import forge.model.FModel;
import forge.screens.FScreen;
import forge.screens.LoadingOverlay;
import forge.screens.TabPageScreen;
import forge.toolbox.FContainer;
import forge.toolbox.FEvent;
import forge.toolbox.FLabel;
import forge.toolbox.GuiChoose;
import forge.util.Callback;
import forge.util.ItemPool;
import forge.util.Localizer;
import forge.util.Utils;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.Map;
public class AdventureDeckEditor extends TabPageScreen<AdventureDeckEditor> {
public static FSkinImage MAIN_DECK_ICON = Forge.hdbuttons ? FSkinImage.HDLIBRARY :FSkinImage.DECKLIST;
public static FSkinImage SIDEBOARD_ICON = Forge.hdbuttons ? FSkinImage.HDSIDEBOARD : FSkinImage.FLASHBACK;
private static final float HEADER_HEIGHT = Math.round(Utils.AVG_FINGER_HEIGHT * 0.8f);
private static ItemPool<InventoryItem> decksUsingMyCards=new ItemPool<>(InventoryItem.class);
@Override
public void onActivate() {
decksUsingMyCards = new ItemPool<>(InventoryItem.class);
for (int i=0;i<AdventurePlayer.NUMBER_OF_DECKS;i++)
{
final Deck deck = AdventurePlayer.current().getDeck(i);
CardPool main = deck.getMain();
for (final Map.Entry<PaperCard, Integer> e : main) {
decksUsingMyCards.add(e.getKey());
}
if (deck.has(DeckSection.Sideboard)) {
for (final Map.Entry<PaperCard, Integer> e : deck.get(DeckSection.Sideboard)) {
// only add card if we haven't already encountered it in main
if (!main.contains(e.getKey())) {
decksUsingMyCards.add(e.getKey());
}
}
}
}
}
public void refresh() {
for(TabPage<AdventureDeckEditor> page:tabPages)
{
if(page instanceof CardManagerPage)
((CardManagerPage)page).refresh();
}
for (TabPage<AdventureDeckEditor> tabPage : tabPages) {
((AdventureDeckEditor.DeckEditorPage)tabPage).initialize();
}
}
private static AdventureDeckEditor.DeckEditorPage[] getPages() {
final Localizer localizer = Localizer.getInstance();
return new AdventureDeckEditor.DeckEditorPage[] {
new AdventureDeckEditor.CatalogPage(ItemManagerConfig.QUEST_EDITOR_POOL, localizer.getMessage("lblInventory"), FSkinImage.QUEST_BOX),
new AdventureDeckEditor.DeckSectionPage(DeckSection.Main, ItemManagerConfig.QUEST_DECK_EDITOR),
new AdventureDeckEditor.DeckSectionPage(DeckSection.Sideboard, ItemManagerConfig.QUEST_DECK_EDITOR)
};
}
private AdventureDeckEditor.CatalogPage catalogPage;
private AdventureDeckEditor.DeckSectionPage mainDeckPage;
private AdventureDeckEditor.DeckSectionPage sideboardPage;
private AdventureDeckEditor.DeckSectionPage commanderPage;
protected final AdventureDeckEditor.DeckHeader deckHeader = add(new AdventureDeckEditor.DeckHeader());
protected final FLabel lblName = deckHeader.add(new FLabel.Builder().font(FSkinFont.get(16)).insets(new Vector2(Utils.scale(5), 0)).build());
private final FLabel btnMoreOptions = deckHeader.add(new FLabel.Builder().text("...").font(FSkinFont.get(20)).align(Align.center).pressedColor(Header.BTN_PRESSED_COLOR).build());
boolean isShop=false;
public AdventureDeckEditor(boolean createAsShop) {
super(e -> {AdventurePlayer.current().getNewCards().clear();AdventureApplicationAdapter.instance.switchToLast();},getPages());
isShop=createAsShop;
//cache specific pages
for (TabPage<AdventureDeckEditor> tabPage : tabPages) {
if (tabPage instanceof AdventureDeckEditor.CatalogPage) {
catalogPage = (AdventureDeckEditor.CatalogPage) tabPage;
}
else if (tabPage instanceof AdventureDeckEditor.DeckSectionPage) {
AdventureDeckEditor.DeckSectionPage deckSectionPage = (AdventureDeckEditor.DeckSectionPage) tabPage;
switch (deckSectionPage.deckSection) {
case Main:
case Schemes:
case Planes:
mainDeckPage = deckSectionPage;
break;
case Sideboard:
sideboardPage = deckSectionPage;
break;
case Commander:
commanderPage = deckSectionPage;
break;
default:
break;
}
}
}
btnMoreOptions.setCommand(new FEvent.FEventHandler() {
@Override
public void handleEvent(FEvent e) {
FPopupMenu menu = new FPopupMenu() {
@Override
protected void buildMenu() {
final Localizer localizer = Localizer.getInstance();
addItem(new FMenuItem(localizer.getMessage("btnCopyToClipboard"), Forge.hdbuttons ? FSkinImage.HDEXPORT : FSkinImage.BLANK, e1 -> FDeckViewer.copyDeckToClipboard(getDeck())));
((AdventureDeckEditor.DeckEditorPage)getSelectedPage()).buildDeckMenu(this);
}
};
menu.show(btnMoreOptions, 0, btnMoreOptions.getHeight());
}
});
}
@Override
protected void doLayout(float startY, float width, float height) {
if (deckHeader.isVisible()) {
deckHeader.setBounds(0, startY, width, HEADER_HEIGHT);
startY += HEADER_HEIGHT;
}
super.doLayout(startY, width, height);
}
public Deck getDeck() {
return AdventurePlayer.current().getSelectedDeck();
}
protected AdventureDeckEditor.CatalogPage getCatalogPage() {
return catalogPage;
}
protected AdventureDeckEditor.DeckSectionPage getMainDeckPage() {
return mainDeckPage;
}
protected AdventureDeckEditor.DeckSectionPage getSideboardPage() {
return sideboardPage;
}
protected AdventureDeckEditor.DeckSectionPage getCommanderPage() {
return commanderPage;
}
@Override
public void onClose(final Callback<Boolean> canCloseCallback) {
}
@Override
public FScreen getLandscapeBackdropScreen() {
return null; //never use backdrop for editor
}
protected class DeckHeader extends FContainer {
private DeckHeader() {
setHeight(HEADER_HEIGHT);
}
@Override
public void drawBackground(Graphics g) {
g.fillRect(Header.BACK_COLOR, 0, 0, getWidth(), HEADER_HEIGHT);
}
@Override
public void drawOverlay(Graphics g) {
float y = HEADER_HEIGHT - Header.LINE_THICKNESS / 2;
g.drawLine(Header.LINE_THICKNESS, Header.LINE_COLOR, 0, y, getWidth(), y);
}
@Override
protected void doLayout(float width, float height) {
float x = 0;
lblName.setBounds(0, 0, width - 2 * height, height);
x += lblName.getWidth();
//noinspection SuspiciousNameCombination
x += height;
//noinspection SuspiciousNameCombination
btnMoreOptions.setBounds(x, 0, height, height);
}
}
protected static abstract class DeckEditorPage extends TabPage<AdventureDeckEditor> {
protected DeckEditorPage(String caption0, FImage icon0) {
super(caption0, icon0);
}
protected void buildDeckMenu(FPopupMenu menu) {
}
protected abstract void initialize();
@Override
public boolean fling(float velocityX, float velocityY) {
return false; //prevent left/right swipe to change tabs since it doesn't play nice with item managers
}
}
protected static abstract class CardManagerPage extends AdventureDeckEditor.DeckEditorPage {
private final ItemManagerConfig config;
protected final CardManager cardManager = add(new CardManager(false));
protected CardManagerPage(ItemManagerConfig config0, String caption0, FImage icon0) {
super(caption0, icon0);
config = config0;
cardManager.setItemActivateHandler(e -> onCardActivated(cardManager.getSelectedItem()));
cardManager.setContextMenuBuilder(new ItemManager.ContextMenuBuilder<PaperCard>() {
@Override
public void buildMenu(final FDropDownMenu menu, final PaperCard card) {
AdventureDeckEditor.CardManagerPage.this.buildMenu(menu, card);
}
});
}
private final Function<Map.Entry<InventoryItem, Integer>, Comparable<?>> fnNewCompare = from -> AdventurePlayer.current().getNewCards().contains(from.getKey()) ? Integer.valueOf(1) : Integer.valueOf(0);
private final Function<Map.Entry<? extends InventoryItem, Integer>, Object> fnNewGet = from -> AdventurePlayer.current().getNewCards().contains(from.getKey()) ? "NEW" : "";
public static final Function<Map.Entry<InventoryItem, Integer>, Comparable<?>> fnDeckCompare = from -> decksUsingMyCards.count(from.getKey());
public static final Function<Map.Entry<? extends InventoryItem, Integer>, Object> fnDeckGet = from -> Integer.valueOf(decksUsingMyCards.count(from.getKey())).toString();
protected void initialize() {
Map<ColumnDef, ItemColumn> colOverrides = new HashMap<>();
ItemColumn.addColOverride(config, colOverrides, ColumnDef.NEW, fnNewCompare, fnNewGet);
ItemColumn.addColOverride(config, colOverrides, ColumnDef.DECKS, fnDeckCompare, fnDeckGet);
cardManager.setup(config, colOverrides);
}
protected boolean canAddCards() {
return true;
}
public void addCard(PaperCard card) {
addCard(card, 1);
}
public void addCard(PaperCard card, int qty) {
if (canAddCards()) {
cardManager.addItem(card, qty);
updateCaption();
}
}
public void removeCard(PaperCard card) {
removeCard(card, 1);
}
public void removeCard(PaperCard card, int qty) {
cardManager.removeItem(card, qty);
updateCaption();
}
public void setCards(CardPool cards) {
cardManager.setItems(cards);
updateCaption();
}
protected void updateCaption() {
}
protected abstract void onCardActivated(PaperCard card);
protected abstract void buildMenu(final FDropDownMenu menu, final PaperCard card);
private ItemPool<PaperCard> getAllowedAdditions(Iterable<Map.Entry<PaperCard, Integer>> itemsToAdd, boolean isAddSource) {
ItemPool<PaperCard> additions = new ItemPool<>(cardManager.getGenericType());
Deck deck = parentScreen.getDeck();
for (Map.Entry<PaperCard, Integer> itemEntry : itemsToAdd) {
PaperCard card = itemEntry.getKey();
int max;
if (deck == null || card == null) {
max = Integer.MAX_VALUE;
}
else if (DeckFormat.canHaveAnyNumberOf(card)) {
max = Integer.MAX_VALUE;
}
else {
max = FModel.getPreferences().getPrefInt(ForgePreferences.FPref.DECK_DEFAULT_CARD_LIMIT);
Integer cardCopies = DeckFormat.canHaveSpecificNumberInDeck(card);
if (cardCopies != null) {
max = cardCopies;
}
max -= deck.getMain().count(card);
if (deck.has(DeckSection.Sideboard)) {
max -= deck.get(DeckSection.Sideboard).count(card);
}
if (deck.has(DeckSection.Commander)) {
max -= deck.get(DeckSection.Commander).count(card);
}
if (deck.has(DeckSection.Planes)) {
max -= deck.get(DeckSection.Planes).count(card);
}
if (deck.has(DeckSection.Schemes)) {
max -= deck.get(DeckSection.Schemes).count(card);
}
}
int qty;
if (isAddSource) {
qty = itemEntry.getValue();
}
else {
try {
qty = parentScreen.getCatalogPage().cardManager.getItemCount(card);
} catch (Exception e) {
//prevent NPE
qty = 0;
}
}
if (qty > max) {
qty = max;
}
if (qty > 0) {
additions.add(card, qty);
}
}
return additions;
}
protected int getMaxMoveQuantity(boolean isAddMenu, boolean isAddSource) {
ItemPool<PaperCard> selectedItemPool = cardManager.getSelectedItemPool();
if (isAddMenu) {
selectedItemPool = getAllowedAdditions(selectedItemPool, isAddSource);
}
if (selectedItemPool.isEmpty()) {
return 0;
}
int max = Integer.MAX_VALUE;
for (Map.Entry<PaperCard, Integer> itemEntry : selectedItemPool) {
if (itemEntry.getValue() < max) {
max = itemEntry.getValue();
}
}
return max;
}
protected void addItem(FDropDownMenu menu, final String verb, String dest, FImage icon, boolean isAddMenu, boolean isAddSource, final Callback<Integer> callback) {
final int max = getMaxMoveQuantity(isAddMenu, isAddSource);
if (max == 0) { return; }
String label = verb;
if (!StringUtils.isEmpty(dest)) {
label += " " + dest;
}
menu.addItem(new FMenuItem(label, icon, e -> {
if (max == 1) {
callback.run(max);
} else {
final Localizer localizer = Localizer.getInstance();
GuiChoose.getInteger(cardManager.getSelectedItem() + " - " + verb + " " + localizer.getMessage("lblHowMany"), 1, max, 20, callback);
}
}));
}
protected void addCommanderItems(final FDropDownMenu menu, final PaperCard card, boolean isAddMenu, boolean isAddSource) {
final Localizer localizer = Localizer.getInstance();
if (parentScreen.getCommanderPage() == null) {
return;
}
boolean isLegalCommander;
String captionSuffix = localizer.getMessage("lblCommander");
isLegalCommander = DeckFormat.Commander.isLegalCommander(card.getRules());
if (isLegalCommander && !parentScreen.getCommanderPage().cardManager.getPool().contains(card)) {
addItem(menu, "Set", "as " + captionSuffix, parentScreen.getCommanderPage().getIcon(), isAddMenu, isAddSource, new Callback<Integer>() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
setCommander(card);
}
});
}
if (canHavePartnerCommander() && card.getRules().canBePartnerCommander()) {
addItem(menu, "Set", "as Partner " + captionSuffix, parentScreen.getCommanderPage().getIcon(), isAddMenu, isAddSource, new Callback<Integer>() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
setPartnerCommander(card);
}
});
}
if (canHaveSignatureSpell() && card.getRules().canBeSignatureSpell()) {
addItem(menu, "Set", "as Signature Spell", FSkinImage.SORCERY, isAddMenu, isAddSource, new Callback<Integer>() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
setSignatureSpell(card);
}
});
}
}
protected boolean needsCommander() {
return parentScreen.getCommanderPage() != null && parentScreen.getDeck().getCommanders().isEmpty();
}
protected boolean canHavePartnerCommander() {
return parentScreen.getCommanderPage() != null && parentScreen.getDeck().getCommanders().size() == 1
&& parentScreen.getDeck().getCommanders().get(0).getRules().canBePartnerCommander();
}
protected boolean canOnlyBePartnerCommander(final PaperCard card) {
if (parentScreen.getCommanderPage() == null) {
return false;
}
byte cmdCI = 0;
for (final PaperCard p : parentScreen.getDeck().getCommanders()) {
cmdCI |= p.getRules().getColorIdentity().getColor();
}
return !card.getRules().getColorIdentity().hasNoColorsExcept(cmdCI);
}
protected boolean canHaveSignatureSpell() {
return parentScreen.getDeck().getOathbreaker() != null;
}
protected void setCommander(PaperCard card) {
if (!cardManager.isInfinite()) {
removeCard(card);
}
CardPool newPool = new CardPool();
newPool.add(card);
parentScreen.getCommanderPage().setCards(newPool);
refresh(); //refresh so cards shown that match commander's color identity
}
protected void setPartnerCommander(PaperCard card) {
if (!cardManager.isInfinite()) {
removeCard(card);
}
parentScreen.getCommanderPage().addCard(card);
refresh(); //refresh so cards shown that match commander's color identity
}
protected void setSignatureSpell(PaperCard card) {
if (!cardManager.isInfinite()) {
removeCard(card);
}
PaperCard signatureSpell = parentScreen.getDeck().getSignatureSpell();
if (signatureSpell != null) {
parentScreen.getCommanderPage().removeCard(signatureSpell); //remove existing signature spell if any
}
parentScreen.getCommanderPage().addCard(card);
//refreshing isn't needed since color identity won't change from signature spell
}
public void refresh() {
//not needed by default
}
@Override
protected void doLayout(float width, float height) {
float x = 0;
if (Forge.isLandscapeMode()) { //add some horizontal padding in landscape mode
x = ItemFilter.PADDING;
width -= 2 * x;
}
cardManager.setBounds(x, 0, width, height);
}
}
protected static class CatalogPage extends AdventureDeckEditor.CardManagerPage {
private boolean initialized, needRefreshWhenShown;
protected CatalogPage(ItemManagerConfig config, String caption0, FImage icon0) {
super(config, caption0, icon0);
}
@Override
protected void initialize() {
if (initialized) { return; } //prevent initializing more than once if deck changes
initialized = true;
super.initialize();
cardManager.setCaption(getItemManagerCaption());
if (!isVisible() ) {
needRefreshWhenShown = true;
return;
}
refresh();
}
@Override
protected boolean canAddCards() {
if (needRefreshWhenShown) { //ensure refreshed before cards added if hasn't been refreshed yet
needRefreshWhenShown = false;
refresh();
}
return !cardManager.isInfinite();
}
protected String getItemManagerCaption() {
final Localizer localizer = Localizer.getInstance();
return localizer.getMessage("lblCards");
}
@Override
public void setVisible(boolean visible0) {
if (isVisible() == visible0) { return; }
super.setVisible(visible0);
if (visible0 && needRefreshWhenShown) {
needRefreshWhenShown = false;
refresh();
}
}
@Override
public void refresh() {
FThreads.invokeInEdtLater(() -> LoadingOverlay.show(Localizer.getInstance().getMessage("lblLoading"), () -> {
final ItemPool<PaperCard> adventurePool = new ItemPool<>(PaperCard.class);
adventurePool.addAll(AdventurePlayer.current().getCards());
// remove bottom cards that are in the deck from the card pool
adventurePool.removeAll(AdventurePlayer.current().getSelectedDeck().getMain());
// remove sideboard cards from the catalog
adventurePool.removeAll(AdventurePlayer.current().getSelectedDeck().getOrCreate(DeckSection.Sideboard));
cardManager.setPool(adventurePool);
}));
}
@Override
protected void onCardActivated(PaperCard card) {
if (getMaxMoveQuantity(true, true) == 0) {
return; //don't add card if maximum copies of card already in deck
}
if (needsCommander()) {
setCommander(card); //handle special case of setting commander
return;
}
if (canOnlyBePartnerCommander(card)) {
return; //don't auto-change commander unexpectedly
}
if (!cardManager.isInfinite()) {
removeCard(card);
}
parentScreen.getMainDeckPage().addCard(card);
}
@Override
protected void buildMenu(final FDropDownMenu menu, final PaperCard card) {
final Localizer localizer = Localizer.getInstance();
if (!needsCommander() && !canOnlyBePartnerCommander(card)) {
addItem(menu, localizer.getMessage("lblAdd"), localizer.getMessage("lblTo") + " " + parentScreen.getMainDeckPage().cardManager.getCaption(), parentScreen.getMainDeckPage().getIcon(), true, true, new Callback<Integer>() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
if (!cardManager.isInfinite()) {
removeCard(card, result);
}
parentScreen.getMainDeckPage().addCard(card, result);
}
});
if (parentScreen.getSideboardPage() != null) {
addItem(menu, localizer.getMessage("lblAdd"), localizer.getMessage("lbltosideboard"), parentScreen.getSideboardPage().getIcon(), true, true, new Callback<Integer>() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
if (!cardManager.isInfinite()) {
removeCard(card, result);
}
parentScreen.getSideboardPage().addCard(card, result);
}
});
}
if(parentScreen.isShop)
{
addItem(menu, "Sell for ", String.valueOf(AdventurePlayer.current().cardSellPrice(card)), parentScreen.getSideboardPage().getIcon(), true, true, new Callback<Integer>() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
if (!cardManager.isInfinite()) {
removeCard(card, result);
}
AdventurePlayer.current().sellCard(card,result);
}
});
}
}
addCommanderItems(menu, card, true, true);
}
@Override
protected void buildDeckMenu(FPopupMenu menu) {
if (cardManager.getConfig().getShowUniqueCardsOption()) {
final Localizer localizer = Localizer.getInstance();
menu.addItem(new FCheckBoxMenuItem(localizer.getMessage("lblUniqueCardsOnly"), cardManager.getWantUnique(), e -> {
boolean wantUnique = !cardManager.getWantUnique();
cardManager.setWantUnique(wantUnique);
refresh();
cardManager.getConfig().setUniqueCardsOnly(wantUnique);
}));
}
}
}
protected static class DeckSectionPage extends AdventureDeckEditor.CardManagerPage {
private final String captionPrefix;
private final DeckSection deckSection;
protected DeckSectionPage(DeckSection deckSection0, ItemManagerConfig config) {
super(config, null, null);
final Localizer localizer = Localizer.getInstance();
deckSection = deckSection0;
switch (deckSection) {
default:
case Main:
captionPrefix = localizer.getMessage("lblMain");
cardManager.setCaption(localizer.getMessage("ttMain"));
icon = MAIN_DECK_ICON;
break;
case Sideboard:
captionPrefix = localizer.getMessage("lblSide");
cardManager.setCaption(localizer.getMessage("lblSideboard"));
icon = SIDEBOARD_ICON;
break;
case Commander:
captionPrefix = localizer.getMessage("lblCommander");
cardManager.setCaption(localizer.getMessage("lblCommander"));
icon = FSkinImage.COMMANDER;
break;
}
}
@Override
protected void initialize() {
super.initialize();
cardManager.setPool(parentScreen.getDeck().getOrCreate(deckSection));
updateCaption();
}
@Override
protected void updateCaption() {
if (deckSection == DeckSection.Commander) {
caption = captionPrefix; //don't display count for commander section since it won't be more than 1
} else {
caption = captionPrefix + " (" + parentScreen.getDeck().get(deckSection).countAll() + ")";
}
}
@Override
protected void onCardActivated(PaperCard card) {
switch (deckSection) {
case Main:
case Planes:
case Schemes:
removeCard(card);
if (parentScreen.getCatalogPage() != null) {
parentScreen.getCatalogPage().addCard(card);
}
break;
case Sideboard:
removeCard(card);
parentScreen.getMainDeckPage().addCard(card);
break;
default:
break;
}
}
@Override
protected void buildMenu(final FDropDownMenu menu, final PaperCard card) {
final Localizer localizer = Localizer.getInstance();
switch (deckSection) {
default:
case Main:
addItem(menu, localizer.getMessage("lblAdd"), null, Forge.hdbuttons ? FSkinImage.HDPLUS : FSkinImage.PLUS, true, false, new Callback<Integer>() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
parentScreen.getCatalogPage().removeCard(card, result);
addCard(card, result);
}
});
addItem(menu, localizer.getMessage("lblRemove"), null, Forge.hdbuttons ? FSkinImage.HDMINUS : FSkinImage.MINUS, false, false, new Callback<Integer>() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
removeCard(card, result);
if (parentScreen.getCatalogPage() != null) {
parentScreen.getCatalogPage().addCard(card, result);
}
}
});
if (parentScreen.getSideboardPage() != null) {
addItem(menu, localizer.getMessage("lblMove"), localizer.getMessage("lbltosideboard"), parentScreen.getSideboardPage().getIcon(), false, false, new Callback<Integer>() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
removeCard(card, result);
parentScreen.getSideboardPage().addCard(card, result);
}
});
}
addCommanderItems(menu, card, false, false);
break;
case Sideboard:
addItem(menu, localizer.getMessage("lblAdd"), null, Forge.hdbuttons ? FSkinImage.HDPLUS : FSkinImage.PLUS, true, false, new Callback<Integer>() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
parentScreen.getCatalogPage().removeCard(card, result);
addCard(card, result);
}
});
addItem(menu, localizer.getMessage("lblRemove"), null, Forge.hdbuttons ? FSkinImage.HDMINUS : FSkinImage.MINUS, false, false, new Callback<Integer>() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
removeCard(card, result);
if (parentScreen.getCatalogPage() != null) {
parentScreen.getCatalogPage().addCard(card, result);
}
}
});
addItem(menu, localizer.getMessage("lblMove"), localizer.getMessage("lblToMainDeck"), parentScreen.getMainDeckPage().getIcon(), false, false, new Callback<Integer>() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
removeCard(card, result);
parentScreen.getMainDeckPage().addCard(card, result);
}
});
addCommanderItems(menu, card, false, false);
break;
case Commander:
if ( isPartnerCommander(card)) {
addItem(menu, localizer.getMessage("lblRemove"), null, Forge.hdbuttons ? FSkinImage.HDMINUS : FSkinImage.MINUS, false, false, new Callback<Integer>() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) {
return;
}
removeCard(card, result);
parentScreen.getCatalogPage().refresh(); //refresh so commander options shown again
parentScreen.setSelectedPage(parentScreen.getCatalogPage());
}
});
}
break;
}
}
private boolean isPartnerCommander(final PaperCard card) {
if (parentScreen.getCommanderPage() == null || parentScreen.getDeck().getCommanders().isEmpty()) {
return false;
}
PaperCard firstCmdr = parentScreen.getDeck().getCommanders().get(0);
return !card.getName().equals(firstCmdr.getName());
}
}
}

View File

@@ -1,83 +1,13 @@
package forge.adventure.scene; package forge.adventure.scene;
import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.Stage;
import forge.adventure.AdventureApplicationAdapter;
import forge.adventure.world.AdventurePlayer;
import forge.deck.Deck;
import forge.deck.FDeckEditor;
import forge.gamemodes.quest.QuestMode;
import forge.gamemodes.quest.QuestSpellShop;
import forge.gamemodes.quest.data.DeckConstructionRules;
import forge.gamemodes.quest.data.QuestData;
import forge.item.PaperCard;
import forge.itemmanager.ColumnDef;
import forge.itemmanager.ItemColumn;
import forge.itemmanager.ItemManagerConfig;
import forge.model.FModel;
import forge.screens.FScreen; import forge.screens.FScreen;
import forge.toolbox.FEvent;
import java.util.HashMap;
import java.util.Map;
/** /**
* DeckEditScene * DeckEditScene
* scene class that contains the Deck editor * scene class that contains the Deck editor
*/ */
public class DeckEditScene extends ForgeScene { public class DeckEditScene extends ForgeScene {
public class AdventureDeckEditor extends FDeckEditor {
public AdventureDeckEditor( ) {
super( EditorType.Quest, "", false, new FEvent.FEventHandler() {
@Override
public void handleEvent(FEvent e) {
AdventureApplicationAdapter.instance.switchToLast();
}
});
}
@Override
public void onActivate() {
super.onActivate();
QuestSpellShop.updateDecksForEachCard();
}
@Override
protected boolean allowDelete() {
return false;
}
@Override
protected boolean allowsSave() {
return false;
}
@Override
protected boolean allowsAddBasic() {
return false;
}
@Override
protected boolean allowRename() {
return false;
}
@Override
protected boolean isLimitedEditor() {
return true;
}
@Override
protected Map<ColumnDef, ItemColumn> getColOverrides(ItemManagerConfig config) {
Map<ColumnDef, ItemColumn> colOverrides = new HashMap<>();
ItemColumn.addColOverride(config, colOverrides, ColumnDef.NEW, FModel.getQuest().getCards().getFnNewCompare(), FModel.getQuest().getCards().getFnNewGet());
ItemColumn.addColOverride(config, colOverrides, ColumnDef.DECKS, QuestSpellShop.fnDeckCompare, QuestSpellShop.fnDeckGet);
return colOverrides;
}
public void refresh() {
for(TabPage page:tabPages)
{
if(page instanceof CardManagerPage)
((CardManagerPage)page).refresh();
}
}
}
AdventureDeckEditor screen; AdventureDeckEditor screen;
Stage stage; Stage stage;
@@ -96,35 +26,14 @@ public class DeckEditScene extends ForgeScene {
@Override @Override
public void enter() { public void enter() {
QuestData data = new QuestData("", 0, QuestMode.Classic, null, false, "", DeckConstructionRules.Commander);
FModel.getQuest().load(data);
FModel.getQuest().getCards().getCardpool().clear();
for (Map.Entry<PaperCard, Integer> card : AdventurePlayer.current().getCards())
FModel.getQuest().getCards().addSingleCard(card.getKey(), card.getValue());
Deck deck = AdventurePlayer.current().getSelectedDeck();
getScreen(); getScreen();
screen.getEditorType().getController().setDeck(deck);
screen.refresh(); screen.refresh();
super.enter(); super.enter();
} }
@Override @Override
public FScreen getScreen() { public FScreen getScreen() {
return screen==null?screen = new AdventureDeckEditor():screen; return screen==null?screen = new AdventureDeckEditor(true):screen;
} }
} }

View File

@@ -35,9 +35,14 @@ public class InnScene extends UIScene {
super.resLoaded(); super.resLoaded();
ui.onButtonPress("done",()->done()); ui.onButtonPress("done",()->done());
ui.onButtonPress("heal",()->heal()); ui.onButtonPress("heal",()->heal());
ui.onButtonPress("sell",()->sell());
TextButton doneButton = ui.findActor("done"); TextButton doneButton = ui.findActor("done");
} }
private void sell() {
AdventureApplicationAdapter.instance.switchScene(SceneType.ShopScene.instance);
}
@Override @Override
public boolean keyPressed(int keycode) public boolean keyPressed(int keycode)
{ {

View File

@@ -14,7 +14,8 @@ public enum SceneType {
TileMapScene(new forge.adventure.scene.TileMapScene()), TileMapScene(new forge.adventure.scene.TileMapScene()),
RewardScene(new forge.adventure.scene.RewardScene()), RewardScene(new forge.adventure.scene.RewardScene()),
InnScene(new forge.adventure.scene.InnScene()), InnScene(new forge.adventure.scene.InnScene()),
DeckSelectScene(new forge.adventure.scene.DeckSelectScene()); DeckSelectScene(new forge.adventure.scene.DeckSelectScene()),
ShopScene(new forge.adventure.scene.ShopScene());
public final forge.adventure.scene.Scene instance; public final forge.adventure.scene.Scene instance;

View File

@@ -0,0 +1,39 @@
package forge.adventure.scene;
import com.badlogic.gdx.scenes.scene2d.Stage;
import forge.screens.FScreen;
/**
* DeckEditScene
* scene class that contains the Deck editor
*/
public class ShopScene extends ForgeScene {
AdventureDeckEditor screen;
Stage stage;
public ShopScene() {
}
@Override
public void dispose() {
if (stage != null)
stage.dispose();
}
@Override
public void enter() {
getScreen();
screen.refresh();
super.enter();
}
@Override
public FScreen getScreen() {
return screen==null?screen = new AdventureDeckEditor(true):screen;
}
}

View File

@@ -9,6 +9,9 @@ import forge.adventure.util.*;
import forge.deck.CardPool; import forge.deck.CardPool;
import forge.deck.Deck; import forge.deck.Deck;
import forge.deck.DeckSection; import forge.deck.DeckSection;
import forge.item.InventoryItem;
import forge.item.PaperCard;
import forge.util.ItemPool;
import java.io.Serializable; import java.io.Serializable;
@@ -43,6 +46,7 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
return WorldSave.currentSave.getPlayer(); return WorldSave.currentSave.getPlayer();
} }
private final CardPool cards=new CardPool(); private final CardPool cards=new CardPool();
private final ItemPool<InventoryItem> newCards=new ItemPool<>(InventoryItem.class);
public void create(String n, Deck startingDeck, boolean male, int race, int avatar,DifficultyData difficultyData) { public void create(String n, Deck startingDeck, boolean male, int race, int avatar,DifficultyData difficultyData) {
@@ -57,11 +61,13 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
this.difficultyData.startingDifficulty=difficultyData.startingDifficulty; this.difficultyData.startingDifficulty=difficultyData.startingDifficulty;
this.difficultyData.name=difficultyData.name; this.difficultyData.name=difficultyData.name;
this.difficultyData.enemyLifeFactor=difficultyData.enemyLifeFactor; this.difficultyData.enemyLifeFactor=difficultyData.enemyLifeFactor;
this.difficultyData.sellFactor=difficultyData.sellFactor;
life=maxLife; life=maxLife;
avatarIndex = avatar; avatarIndex = avatar;
heroRace = race; heroRace = race;
isFemale = !male; isFemale = !male;
name = n; name = n;
newCards.clear();
onGoldChangeList.emit(); onGoldChangeList.emit();
onLifeTotalChangeList.emit(); onLifeTotalChangeList.emit();
} }
@@ -117,6 +123,9 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
this.difficultyData.startingDifficulty=data.readBool("startingDifficulty"); this.difficultyData.startingDifficulty=data.readBool("startingDifficulty");
this.difficultyData.name=data.readString("difficultyName"); this.difficultyData.name=data.readString("difficultyName");
this.difficultyData.enemyLifeFactor=data.readFloat("enemyLifeFactor"); this.difficultyData.enemyLifeFactor=data.readFloat("enemyLifeFactor");
this.difficultyData.sellFactor=data.readFloat("sellFactor");
if(this.difficultyData.sellFactor==0)
this.difficultyData.sellFactor=0.2f;
name = data.readString("name"); name = data.readString("name");
@@ -155,6 +164,7 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
cards.clear(); cards.clear();
cards.addAll(CardPool.fromCardList(Lists.newArrayList((String[])data.readObject("cards")))); cards.addAll(CardPool.fromCardList(Lists.newArrayList((String[])data.readObject("cards"))));
newCards.clear();
onLifeTotalChangeList.emit(); onLifeTotalChangeList.emit();
onGoldChangeList.emit(); onGoldChangeList.emit();
} }
@@ -169,6 +179,7 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
data.store("startingDifficulty",this.difficultyData.startingDifficulty); data.store("startingDifficulty",this.difficultyData.startingDifficulty);
data.store("difficultyName",this.difficultyData.name); data.store("difficultyName",this.difficultyData.name);
data.store("enemyLifeFactor",this.difficultyData.enemyLifeFactor); data.store("enemyLifeFactor",this.difficultyData.enemyLifeFactor);
data.store("sellFactor",this.difficultyData.sellFactor);
data.store("name",name); data.store("name",name);
@@ -220,6 +231,7 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
{ {
case Card: case Card:
cards.add(reward.getCard()); cards.add(reward.getCard());
newCards.add(reward.getCard());
break; break;
case Gold: case Gold:
addGold(reward.getCount()); addGold(reward.getCount());
@@ -297,4 +309,19 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
deck = (Deck)deck.copyTo(text); deck = (Deck)deck.copyTo(text);
decks[selectedDeckIndex]=deck; decks[selectedDeckIndex]=deck;
} }
public ItemPool<InventoryItem> getNewCards() {
return newCards;
}
public int cardSellPrice(PaperCard card)
{
return (int) (CardUtil.getCardPrice(card)*difficultyData.sellFactor);
}
public void sellCard(PaperCard card, Integer result) {
float price= CardUtil.getCardPrice(card)*result;
price=difficultyData.sellFactor*price;
cards.remove(card, result);
addGold((int) price);
}
} }

View File

@@ -737,7 +737,7 @@ public class AiController {
} }
int oldCMC = -1; int oldCMC = -1;
boolean xCost = sa.getPayCosts().hasXInAnyCostPart() || sa.getHostCard().hasStartOfKeyword("Strive"); boolean xCost = sa.costHasX() || sa.getHostCard().hasStartOfKeyword("Strive");
if (!xCost) { if (!xCost) {
if (!ComputerUtilCost.canPayCost(sa, player)) { if (!ComputerUtilCost.canPayCost(sa, player)) {
// for most costs, it's OK to check if they can be paid early in order to avoid running a heavy API check // for most costs, it's OK to check if they can be paid early in order to avoid running a heavy API check

View File

@@ -722,7 +722,12 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
return CardType.isALandType(input); return CardType.isALandType(input);
} }
}; };
public static Predicate<String> IS_BASIC_LAND_TYPE = new Predicate<String>() {
@Override
public boolean apply(String input) {
return CardType.isABasicLandType(input);
}
};
public static Predicate<String> IS_ARTIFACT_TYPE = new Predicate<String>() { public static Predicate<String> IS_ARTIFACT_TYPE = new Predicate<String>() {
@Override @Override
public boolean apply(String input) { public boolean apply(String input) {

View File

@@ -28,7 +28,6 @@ public class ImmediateTriggerEffect extends SpellAbilityEffect {
} }
return ""; return "";
} }
@Override @Override

View File

@@ -5139,12 +5139,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
} }
public final boolean hasABasicLandType() { public final boolean hasABasicLandType() {
for (final String type : getType().getSubtypes()) { return Iterables.any(getType().getSubtypes(), CardType.Predicates.IS_BASIC_LAND_TYPE);
if (forge.card.CardType.isABasicLandType(type)) {
return true;
}
}
return false;
} }
public final boolean isUsedToPay() { public final boolean isUsedToPay() {

View File

@@ -185,11 +185,9 @@ public class TokenInfo {
} }
} }
if (!typeMap.isEmpty()) { if (!typeMap.isEmpty()) {
String oldName = result.getName();
CardType type = new CardType(result.getType()); CardType type = new CardType(result.getType());
String joinedName = StringUtils.join(type.getSubtypes(), " "); final boolean nameGenerated = result.getName().endsWith(" Token");
final boolean nameGenerated = oldName.equals(joinedName);
boolean typeChanged = false; boolean typeChanged = false;
if (!Iterables.isEmpty(type.getSubtypes())) { if (!Iterables.isEmpty(type.getSubtypes())) {
@@ -207,7 +205,7 @@ public class TokenInfo {
// update generated Name // update generated Name
if (nameGenerated) { if (nameGenerated) {
result.setName(StringUtils.join(type.getSubtypes(), " ")); result.setName(StringUtils.join(type.getSubtypes(), " ") + " Token");
} }
} }
} }

View File

@@ -48,7 +48,7 @@ public class GameSimulatorTest extends SimulationTestCase {
assertEquals(1, heraldCopy.getToughnessBonusFromCounters()); assertEquals(1, heraldCopy.getToughnessBonusFromCounters());
assertEquals(1, heraldCopy.getPowerBonusFromCounters()); assertEquals(1, heraldCopy.getPowerBonusFromCounters());
Card warriorToken = findCardWithName(simGame, "Warrior"); Card warriorToken = findCardWithName(simGame, "Warrior Token");
assertNotNull(warriorToken); assertNotNull(warriorToken);
assertTrue(warriorToken.isSick()); assertTrue(warriorToken.isSick());
assertEquals(1, warriorToken.getCurrentPower()); assertEquals(1, warriorToken.getCurrentPower());
@@ -233,7 +233,7 @@ public class GameSimulatorTest extends SimulationTestCase {
GameSimulator sim = createSimulator(game, p); GameSimulator sim = createSimulator(game, p);
sim.simulateSpellAbility(minusTwo); sim.simulateSpellAbility(minusTwo);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
Card vampireToken = findCardWithName(simGame, "Vampire"); Card vampireToken = findCardWithName(simGame, "Vampire Token");
assertNotNull(vampireToken); assertNotNull(vampireToken);
Player simP = simGame.getPlayers().get(1); Player simP = simGame.getPlayers().get(1);
@@ -599,7 +599,7 @@ public class GameSimulatorTest extends SimulationTestCase {
assertTrue(score > 0); assertTrue(score > 0);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
Card scion = findCardWithName(simGame, "Eldrazi Scion"); Card scion = findCardWithName(simGame, "Eldrazi Scion Token");
assertNotNull(scion); assertNotNull(scion);
assertEquals(1, scion.getNetPower()); assertEquals(1, scion.getNetPower());
assertEquals(1, scion.getNetToughness()); assertEquals(1, scion.getNetToughness());
@@ -608,7 +608,7 @@ public class GameSimulatorTest extends SimulationTestCase {
GameCopier copier = new GameCopier(simGame); GameCopier copier = new GameCopier(simGame);
Game copy = copier.makeCopy(); Game copy = copier.makeCopy();
Card scionCopy = findCardWithName(copy, "Eldrazi Scion"); Card scionCopy = findCardWithName(copy, "Eldrazi Scion Token");
assertNotNull(scionCopy); assertNotNull(scionCopy);
assertEquals(1, scionCopy.getNetPower()); assertEquals(1, scionCopy.getNetPower());
assertEquals(1, scionCopy.getNetToughness()); assertEquals(1, scionCopy.getNetToughness());
@@ -1288,7 +1288,7 @@ public class GameSimulatorTest extends SimulationTestCase {
assertTrue(score > 0); assertTrue(score > 0);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
int numZombies = countCardsWithName(simGame, "Zombie"); int numZombies = countCardsWithName(simGame, "Zombie Token");
assertEquals(2, numZombies); assertEquals(2, numZombies);
} }
@@ -1323,11 +1323,11 @@ public class GameSimulatorTest extends SimulationTestCase {
GameSimulator sim = createSimulator(game, p); GameSimulator sim = createSimulator(game, p);
int score = sim.simulateSpellAbility(fatalPushSA).value; int score = sim.simulateSpellAbility(fatalPushSA).value;
assertTrue(score > 0); assertTrue(score > 0);
assertEquals(2, countCardsWithName(sim.getSimulatedGameState(), "Zombie")); assertEquals(2, countCardsWithName(sim.getSimulatedGameState(), "Zombie Token"));
score = sim.simulateSpellAbility(electrifySA).value; score = sim.simulateSpellAbility(electrifySA).value;
assertTrue(score > 0); assertTrue(score > 0);
assertEquals(countCardsWithName(sim.getSimulatedGameState(), "Zombie"), 4); assertEquals(4, countCardsWithName(sim.getSimulatedGameState(), "Zombie Token"));
} }
public void testPlayerXCount() { public void testPlayerXCount() {
@@ -1564,7 +1564,7 @@ public class GameSimulatorTest extends SimulationTestCase {
assertTrue(score > 0); assertTrue(score > 0);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
int numZombies = countCardsWithName(simGame, "Zombie"); int numZombies = countCardsWithName(simGame, "Zombie Token");
assertEquals(4, numZombies); assertEquals(4, numZombies);
} }
@@ -1592,7 +1592,7 @@ public class GameSimulatorTest extends SimulationTestCase {
assertTrue(score > 0); assertTrue(score > 0);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
int numZombies = countCardsWithName(simGame, "Zombie"); int numZombies = countCardsWithName(simGame, "Zombie Token");
assertEquals(3, numZombies); assertEquals(3, numZombies);
} }

View File

@@ -438,20 +438,21 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
setSelectedPage(getMainDeckPage()); //select main deck page if needed so main deck if visible below dialog setSelectedPage(getMainDeckPage()); //select main deck page if needed so main deck if visible below dialog
} }
})); }));
addItem(new FMenuItem(localizer.getMessage("lblSaveAs"), Forge.hdbuttons ? FSkinImage.HDSAVEAS : FSkinImage.SAVEAS, new FEventHandler() { if(allowsSave())
@Override addItem(new FMenuItem(localizer.getMessage("lblSaveAs"), Forge.hdbuttons ? FSkinImage.HDSAVEAS : FSkinImage.SAVEAS, new FEventHandler() {
public void handleEvent(FEvent e) { @Override
String defaultName = editorType.getController().getNextAvailableName(); public void handleEvent(FEvent e) {
FOptionPane.showInputDialog(localizer.getMessage("lblNameNewCopyDeck"), defaultName, new Callback<String>() { String defaultName = editorType.getController().getNextAvailableName();
@Override FOptionPane.showInputDialog(localizer.getMessage("lblNameNewCopyDeck"), defaultName, new Callback<String>() {
public void run(String result) { @Override
if (!StringUtils.isEmpty(result)) { public void run(String result) {
editorType.getController().saveAs(result); if (!StringUtils.isEmpty(result)) {
editorType.getController().saveAs(result);
}
} }
} });
}); }
} }));
}));
} }
if (allowRename()) { if (allowRename()) {
addItem(new FMenuItem(localizer.getMessage("lblRenameDeck"), Forge.hdbuttons ? FSkinImage.HDEDIT : FSkinImage.EDIT, new FEventHandler() { addItem(new FMenuItem(localizer.getMessage("lblRenameDeck"), Forge.hdbuttons ? FSkinImage.HDEDIT : FSkinImage.EDIT, new FEventHandler() {
@@ -767,7 +768,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
} }
protected void initialize() { protected void initialize() {
cardManager.setup(config, parentScreen.getColOverrides(config)); cardManager.setup(config);
} }
protected boolean canAddCards() { protected boolean canAddCards() {
@@ -1256,6 +1257,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
} }
} }
addCommanderItems(menu, card, true, true); addCommanderItems(menu, card, true, true);
if (parentScreen.getEditorType() == EditorType.Constructed) { if (parentScreen.getEditorType() == EditorType.Constructed) {

View File

@@ -19,18 +19,21 @@
"name":"Easy", "name":"Easy",
"startingLife":16, "startingLife":16,
"staringMoney":200, "staringMoney":200,
"enemyLifeFactor":0.8 "enemyLifeFactor":0.8 ,
"sellFactor":0.5
},{ },{
"name":"Normal", "name":"Normal",
"startingLife":12, "startingLife":12,
"staringMoney":100, "staringMoney":100,
"startingDifficulty":true, "startingDifficulty":true,
"enemyLifeFactor":1.0 "enemyLifeFactor":1.0 ,
"sellFactor":0.2
},{ },{
"name":"Hard", "name":"Hard",
"startingLife":8, "startingLife":8,
"staringMoney":10, "staringMoney":10,
"enemyLifeFactor":1.5 "enemyLifeFactor":1.5 ,
"sellFactor":0.1
} }
] ]
} }

View File

@@ -20,6 +20,15 @@
"x": 420, "x": 420,
"y": 10 "y": 10
} , } ,
{
"type" : "TextButton",
"name" : "sell" ,
"text" : "Sell cards" ,
"width": 48,
"height": 16,
"x": 420,
"y": 34
} ,
{ {
"type" : "TextButton", "type" : "TextButton",
"name" : "done" , "name" : "done" ,
@@ -27,7 +36,7 @@
"width": 48, "width": 48,
"height": 16, "height": 16,
"x": 420, "x": 420,
"y": 34 "y": 58
} }
] ]

View File

@@ -5,11 +5,11 @@ PT:4/4
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield or dies, exile another card from a graveyard. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield or dies, exile another card from a graveyard.
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigExile | Secondary$ True | TriggerDescription$ When CARDNAME enters the battlefield or dies, exile another card from a graveyard. T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigExile | Secondary$ True | TriggerDescription$ When CARDNAME enters the battlefield or dies, exile another card from a graveyard.
SVar:TrigExile:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | Hidden$ True | RememberChanged$ True | ChangeType$ Card.Other | ChangeNum$ 1 | Mandatory$ True | AILogic$ ExilePreference:HighestCMC | SubAbility$ DBImmediateTrigger SVar:TrigExile:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | Hidden$ True | RememberChanged$ True | ChangeType$ Card.Other | ChangeNum$ 1 | Mandatory$ True | AILogic$ ExilePreference:HighestCMC | SubAbility$ DBImmediateTrigger
SVar:DBImmediateTrigger:DB$ ImmediateTrigger | ConditionDefined$ Remembered | ConditionPresent$ Card | Execute$ TrigCharm | TriggerDescription$ When you do, ABILITY SVar:DBImmediateTrigger:DB$ ImmediateTrigger | ConditionDefined$ Remembered | ConditionPresent$ Card | RememberObjects$ Remembered | SubAbility$ DBCleanup | Execute$ TrigCharm | TriggerDescription$ When you do, ABILITY
SVar:TrigCharm:DB$ Charm | Choices$ DBRemoveCounter,DBPump SVar:TrigCharm:DB$ Charm | Choices$ DBRemoveCounter,DBPump
SVar:DBRemoveCounter:DB$ RemoveCounter | ValidTgts$ Permanent | TgtPrompt$ Select target permanent | CounterType$ Any | CounterNum$ X | SubAbility$ DBCleanup | SpellDescription$ Remove X counters from target permanent, where X is the mana value of the exiled card. SVar:DBRemoveCounter:DB$ RemoveCounter | ValidTgts$ Permanent | TgtPrompt$ Select target permanent | CounterType$ Any | CounterNum$ X | SpellDescription$ Remove X counters from target permanent, where X is the mana value of the exiled card.
SVar:DBPump:DB$ Pump | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | IsCurse$ True | NumAtt$ -X | NumDef$ -X | SubAbility$ DBCleanup | SpellDescription$ Target creature an opponent controls gets -X/-X until end of turn, where X is the mana value of the exiled card. SVar:DBPump:DB$ Pump | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | IsCurse$ True | NumAtt$ -X | NumDef$ -X | SpellDescription$ Target creature an opponent controls gets -X/-X until end of turn, where X is the mana value of the exiled card.
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Remembered$CardManaCost SVar:X:TriggerRemembered$CardManaCost
DeckHas:Ability$Graveyard DeckHas:Ability$Graveyard
Oracle:Menace\nWhen Cemetery Desecrator enters the battlefield or dies, exile another card from a graveyard. When you do, choose one —\n• Remove X counters from target permanent, where X is the mana value of the exiled card.\n• Target creature an opponent controls gets -X/-X until end of turn, where X is the mana value of the exiled card. Oracle:Menace\nWhen Cemetery Desecrator enters the battlefield or dies, exile another card from a graveyard. When you do, choose one —\n• Remove X counters from target permanent, where X is the mana value of the exiled card.\n• Target creature an opponent controls gets -X/-X until end of turn, where X is the mana value of the exiled card.

View File

@@ -5,5 +5,5 @@ K:Enchant player
A:SP$ Attach | Cost$ R | ValidTgts$ Player | AILogic$ Curse A:SP$ Attach | Cost$ R | ValidTgts$ Player | AILogic$ Curse
T:Mode$ AttackersDeclared | ValidCard$ Creature | AttackedTarget$ Player.EnchantedBy | Execute$ TrigRepeat | TriggerZones$ Battlefield | TriggerDescription$ Whenever enchanted player is attacked, create a Gold token. Each opponent attacking that player does the same. (A Gold token is an artifact with "Sacrifice this artifact: Add one mana of any color.") T:Mode$ AttackersDeclared | ValidCard$ Creature | AttackedTarget$ Player.EnchantedBy | Execute$ TrigRepeat | TriggerZones$ Battlefield | TriggerDescription$ Whenever enchanted player is attacked, create a Gold token. Each opponent attacking that player does the same. (A Gold token is an artifact with "Sacrifice this artifact: Add one mana of any color.")
SVar:TrigRepeat:DB$ RepeatEach | RepeatPlayers$ TriggeredAttackingPlayerAndYou | RepeatSubAbility$ TrigToken | ChangeZoneTable$ True SVar:TrigRepeat:DB$ RepeatEach | RepeatPlayers$ TriggeredAttackingPlayerAndYou | RepeatSubAbility$ TrigToken | ChangeZoneTable$ True
SVar:TrigToken:DB$ Token | TokenScript$ gold | TokenOwner$ Player.IsRemembered | TokenAmount$ 1 | LegacyImage$ gold c17 SVar:TrigToken:DB$ Token | TokenScript$ c_a_gold_draw | TokenOwner$ Player.IsRemembered | TokenAmount$ 1
Oracle:Enchant player\nWhenever enchanted player is attacked, create a Gold token. Each opponent attacking that player does the same. (A Gold token is an artifact with "Sacrifice this artifact: Add one mana of any color.") Oracle:Enchant player\nWhenever enchanted player is attacked, create a Gold token. Each opponent attacking that player does the same. (A Gold token is an artifact with "Sacrifice this artifact: Add one mana of any color.")

View File

@@ -2,5 +2,5 @@ Name:Gild
ManaCost:3 B ManaCost:3 B
Types:Sorcery Types:Sorcery
A:SP$ ChangeZone | Cost$ 3 B | ValidTgts$ Creature | TgtPrompt$ Select target creature | Origin$ Battlefield | Destination$ Exile | SubAbility$ DBToken | SpellDescription$ Exile target creature. Create a Gold token. (It's an artifact with "Sacrifice this artifact: Add one mana of any color.") A:SP$ ChangeZone | Cost$ 3 B | ValidTgts$ Creature | TgtPrompt$ Select target creature | Origin$ Battlefield | Destination$ Exile | SubAbility$ DBToken | SpellDescription$ Exile target creature. Create a Gold token. (It's an artifact with "Sacrifice this artifact: Add one mana of any color.")
SVar:DBToken:DB$ Token | TokenScript$ gold | TokenOwner$ You | LegacyImage$ gold bng SVar:DBToken:DB$ Token | TokenScript$ c_a_gold_draw | TokenOwner$ You
Oracle:Exile target creature. Create a Gold token. (It's an artifact with "Sacrifice this artifact: Add one mana of any color.") Oracle:Exile target creature. Create a Gold token. (It's an artifact with "Sacrifice this artifact: Add one mana of any color.")

View File

@@ -2,11 +2,14 @@ Name:Goblin Welder
ManaCost:R ManaCost:R
Types:Creature Goblin Artificer Types:Creature Goblin Artificer
PT:1/1 PT:1/1
A:AB$ Pump | Cost$ T | ValidTgts$ Artifact | TgtPrompt$ Select target artifact a player controls | RememberObjects$ ThisTargetedCard | Condition$ AllTargetsLegal | SubAbility$ DBTargetYard | SpellDescription$ Choose target artifact a player controls and target artifact card in that player's graveyard. If both targets are still legal as this ability resolves, that player simultaneously sacrifices the artifact and returns the artifact card to the battlefield. | StackDescription$ None A:AB$ Pump | Cost$ T | ValidTgts$ Artifact | TgtPrompt$ Select target artifact a player controls | RememberObjects$ ThisTargetedCard | Condition$ AllTargetsLegal | SubAbility$ DBTargetYard | StackDescription$ If both targets are still legal as this ability resolves, {p:TargetedController} simultaneously sacrifices {c:ThisTargetedCard} | SpellDescription$ Choose target artifact a player controls and target artifact card in that player's graveyard. If both targets are still legal as this ability resolves, that player simultaneously sacrifices the artifact and returns the artifact card to the battlefield.
SVar:DBTargetYard:DB$ Pump | ValidTgts$ Artifact | TgtPrompt$ Select target artifact card in that player's graveyard | TgtZone$ Graveyard | PumpZone$ Graveyard | TargetsWithSameController$ True | ImprintCards$ ThisTargetedCard | Condition$ AllTargetsLegal | StackDescription$ If both targets are still legal as this ability resolves, {p:TargetedController} simultaneously sacrifices {c:ParentTarget} and returns {c:Targeted} to the battlefield. | SubAbility$ DBSacrifice SVar:DBTargetYard:DB$ Pump | ValidTgts$ Artifact | TargetsWithDefinedController$ ParentTargetedController | TgtPrompt$ Select target artifact card in that player's graveyard | TgtZone$ Graveyard | PumpZone$ Graveyard | ImprintCards$ ThisTargetedCard | Condition$ AllTargetsLegal | StackDescription$ and returns {c:ThisTargetedCard} to the battlefield. | SubAbility$ DBBranch
SVar:DBSacrifice:DB$ SacrificeAll | ValidCards$ Card.IsRemembered | ConditionDefined$ Remembered | ConditionPresent$ Artifact | ConditionCompare$ GE1 | ConditionCheckSVar$ CheckImprint | ConditionSVarCompare$ GE1 | SubAbility$ DBReturn | StackDescription$ None SVar:DBBranch:DB$ Branch | BranchConditionSVar$ TargetCheck | BranchConditionSVarCompare$ GE2 | TrueSubAbility$ DBSacrifice | FalseSubAbility$ DBCleanup
SVar:DBReturn:DB$ ChangeZone | Defined$ Imprinted | Origin$ Graveyard | Destination$ Battlefield | SubAbility$ DBCleanup | ConditionDefined$ Remembered | ConditionPresent$ Artifact | ConditionCompare$ GE1 | ConditionCheckSVar$ CheckImprint | ConditionSVarCompare$ GE1 | StackDescription$ None SVar:DBSacrifice:DB$ SacrificeAll | ValidCards$ Card.IsRemembered | SubAbility$ DBReturn
SVar:DBReturn:DB$ ChangeZone | Defined$ Imprinted | Origin$ Graveyard | Destination$ Battlefield | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True
SVar:TargetCheck:SVar$CheckRemem/Plus.CheckImprint
SVar:CheckRemem:Remembered$Valid Artifact.sharesControllerWith Imprinted
SVar:CheckImprint:Imprinted$Valid Artifact.sharesControllerWith Remembered SVar:CheckImprint:Imprinted$Valid Artifact.sharesControllerWith Remembered
AI:RemoveDeck:All AI:RemoveDeck:All
AI:RemoveDeck:Random AI:RemoveDeck:Random

View File

@@ -4,7 +4,7 @@ Types:Legendary Creature Human Noble
PT:2/3 PT:2/3
T:Mode$ Untaps | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigExile | OptionalDecider$ You | TriggerDescription$ Inspired — Whenever CARDNAME becomes untapped, you may exile target creature. If you do, create a Gold token. (It's an artifact with "Sacrifice this artifact: Add one mana of any color.") T:Mode$ Untaps | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigExile | OptionalDecider$ You | TriggerDescription$ Inspired — Whenever CARDNAME becomes untapped, you may exile target creature. If you do, create a Gold token. (It's an artifact with "Sacrifice this artifact: Add one mana of any color.")
SVar:TrigExile:DB$ ChangeZone | ValidTgts$ Creature | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | SubAbility$ DBToken SVar:TrigExile:DB$ ChangeZone | ValidTgts$ Creature | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | SubAbility$ DBToken
SVar:DBToken:DB$ Token | TokenScript$ gold | TokenOwner$ You | TokenAmount$ 1 | LegacyImage$ gold jou | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | SubAbility$ DBCleanup SVar:DBToken:DB$ Token | TokenScript$ c_a_gold_draw | TokenOwner$ You | TokenAmount$ 1 | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Remembered$Amount SVar:X:Remembered$Amount
Oracle:Inspired — Whenever King Macar, the Gold-Cursed becomes untapped, you may exile target creature. If you do, create a Gold token. (It's an artifact with "Sacrifice this artifact: Add one mana of any color.") Oracle:Inspired — Whenever King Macar, the Gold-Cursed becomes untapped, you may exile target creature. If you do, create a Gold token. (It's an artifact with "Sacrifice this artifact: Add one mana of any color.")

View File

@@ -3,7 +3,7 @@ ManaCost:X W U U
Types:Legendary Planeswalker Niko Types:Legendary Planeswalker Niko
Loyalty:3 Loyalty:3
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield, create X Shard tokens. (They're enchantments with "{2}, Sacrifice this enchantment: Scry 1, then draw a card.") T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield, create X Shard tokens. (They're enchantments with "{2}, Sacrifice this enchantment: Scry 1, then draw a card.")
SVar:TrigToken:DB$ Token | TokenAmount$ X | TokenScript$ shard | TokenOwner$ You SVar:TrigToken:DB$ Token | TokenAmount$ X | TokenScript$ c_e_shard_draw | TokenOwner$ You
SVar:X:Count$xPaid SVar:X:Count$xPaid
A:AB$ Effect | Cost$ AddCounter<1/LOYALTY> | Name$ Niko Aris Effect | Planeswalker$ True | Triggers$ Trig | TargetMin$ 0 | TargetMax$ 1 | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | RememberObjects$ Targeted | SubAbility$ DBPump | SpellDescription$ Up to one target creature you control can't be blocked this turn. Whenever that creature deals damage this turn, return it to its owner's hand. A:AB$ Effect | Cost$ AddCounter<1/LOYALTY> | Name$ Niko Aris Effect | Planeswalker$ True | Triggers$ Trig | TargetMin$ 0 | TargetMax$ 1 | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | RememberObjects$ Targeted | SubAbility$ DBPump | SpellDescription$ Up to one target creature you control can't be blocked this turn. Whenever that creature deals damage this turn, return it to its owner's hand.
SVar:DBPump:DB$ Pump | KW$ HIDDEN Unblockable | Defined$ Targeted SVar:DBPump:DB$ Pump | KW$ HIDDEN Unblockable | Defined$ Targeted
@@ -11,6 +11,6 @@ SVar:Trig:Mode$ DamageDealtOnce | ValidSource$ Creature.IsRemembered | Execute$
SVar:Eff:DB$ ChangeZone | ValidTgts$ Creature.IsRemembered | Origin$ Battlefield | Destination$ Hand SVar:Eff:DB$ ChangeZone | ValidTgts$ Creature.IsRemembered | Origin$ Battlefield | Destination$ Hand
A:AB$ DealDamage | Cost$ SubCounter<1/LOYALTY> | Planeswalker$ True | ValidTgts$ Creature.tapped | NumDmg$ Y | TgtPrompt$ Select target tapped creature | SpellDescription$ CARDNAME deals 2 damage to target tapped creature for each card you've drawn this turn. A:AB$ DealDamage | Cost$ SubCounter<1/LOYALTY> | Planeswalker$ True | ValidTgts$ Creature.tapped | NumDmg$ Y | TgtPrompt$ Select target tapped creature | SpellDescription$ CARDNAME deals 2 damage to target tapped creature for each card you've drawn this turn.
SVar:Y:Count$YouDrewThisTurn/Twice SVar:Y:Count$YouDrewThisTurn/Twice
A:AB$ Token | Cost$ SubCounter<1/LOYALTY> | Planeswalker$ True | TokenAmount$ 1 | TokenScript$ shard | TokenOwner$ You | SpellDescription$ Create a Shard token. A:AB$ Token | Cost$ SubCounter<1/LOYALTY> | Planeswalker$ True | TokenAmount$ 1 | TokenScript$ c_e_shard_draw | TokenOwner$ You | SpellDescription$ Create a Shard token.
DeckHas:Ability$Token & Ability$Sacrifice DeckHas:Ability$Token & Ability$Sacrifice
Oracle:When Niko Aris enters the battlefield, create X Shard tokens. (They're enchantments with "{2}, Sacrifice this enchantment: Scry 1, then draw a card.")\n[+1]: Up to one target creature you control can't be blocked this turn. Whenever that creature deals damage this turn, return it to its owner's hand.\n[1]: Niko Aris deals 2 damage to target tapped creature for each card you've drawn this turn.\n[1]: Create a Shard token. Oracle:When Niko Aris enters the battlefield, create X Shard tokens. (They're enchantments with "{2}, Sacrifice this enchantment: Scry 1, then draw a card.")\n[+1]: Up to one target creature you control can't be blocked this turn. Whenever that creature deals damage this turn, return it to its owner's hand.\n[1]: Niko Aris deals 2 damage to target tapped creature for each card you've drawn this turn.\n[1]: Create a Shard token.

View File

@@ -5,6 +5,6 @@ K:Saga:4:TrigToken,TrigPutCounter,TrigDraw,TrigGold
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_1_1_human_soldier | TokenOwner$ You | LegacyImage$ w 1 1 human soldier thb | SpellDescription$ Create a 1/1 white Human Soldier token. SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_1_1_human_soldier | TokenOwner$ You | LegacyImage$ w 1 1 human soldier thb | SpellDescription$ Create a 1/1 white Human Soldier token.
SVar:TrigPutCounter:DB$ PutCounter | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | CounterType$ P1P1 | CounterNum$ 3 | SpellDescription$ Put three +1/+1 counters on target creature you control. SVar:TrigPutCounter:DB$ PutCounter | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | CounterType$ P1P1 | CounterNum$ 3 | SpellDescription$ Put three +1/+1 counters on target creature you control.
SVar:TrigDraw:DB$ Draw | NumCards$ 2 | ConditionPresent$ Creature.YouCtrl+powerGE4 | SpellDescription$ If you control a creature with power 4 or greater, draw two cards. SVar:TrigDraw:DB$ Draw | NumCards$ 2 | ConditionPresent$ Creature.YouCtrl+powerGE4 | SpellDescription$ If you control a creature with power 4 or greater, draw two cards.
SVar:TrigGold:DB$ Token | TokenAmount$ 1 | TokenScript$ gold | TokenOwner$ You | LegacyImage$ gold thb | SpellDescription$ Create a Gold token. SVar:TrigGold:DB$ Token | TokenAmount$ 1 | TokenScript$ c_a_gold_draw | TokenOwner$ You | SpellDescription$ Create a Gold token.
DeckHas:Ability$Counters & Ability$Token DeckHas:Ability$Counters & Ability$Token
Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after IV.)\nI — Create a 1/1 white Human Soldier creature token.\nII — Put three +1/+1 counters on target creature you control.\nIII — If you control a creature with power 4 or greater, draw two cards.\nIV — Create a Gold token. (It's an artifact with "Sacrifice this artifact: Add one mana of any color.") Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after IV.)\nI — Create a 1/1 white Human Soldier creature token.\nII — Put three +1/+1 counters on target creature you control.\nIII — If you control a creature with power 4 or greater, draw two cards.\nIV — Create a Gold token. (It's an artifact with "Sacrifice this artifact: Add one mana of any color.")

View File

@@ -178,14 +178,14 @@ ScryfallCode=BNG
165 R Temple of Plenty @Noah Bradley 165 R Temple of Plenty @Noah Bradley
[tokens] [tokens]
gold b_2_2_e_zombie
c_a_gold_draw
g_2_2_wolf
g_3_3_e_centaur
r_3_1_e_elemental_haste
u_2_2_e_bird_flying
u_9_9_kraken
w_1_1_bird_flying w_1_1_bird_flying
w_1_1_cat_soldier_vigilance w_1_1_cat_soldier_vigilance
w_1_1_e_soldier w_1_1_e_soldier
w_1_1_e_soldier w_1_1_e_soldier
u_2_2_e_bird_flying
u_9_9_kraken
b_2_2_e_zombie
r_3_1_e_elemental_haste
g_3_3_e_centaur
g_2_2_wolf

View File

@@ -352,27 +352,27 @@ ScryfallCode=C15
342 L Forest @Jonas De Ro 342 L Forest @Jonas De Ro
[tokens] [tokens]
gold
lightning_rager
c_1_1_shapeshifter_changeling
w_4_4_angel_flying
w_2_2_cat
w_2_2_knight_first_strike
w_2_2_knight_vigilance
u_2_2_drake_flying
b_0_0_phyrexian_germ b_0_0_phyrexian_germ
b_2_2_zombie b_2_2_zombie
r_5_5_dragon_flying c_1_1_shapeshifter_changeling
r_3_1_elemental_shaman_haste c_a_gold_draw
g_2_2_bear
g_4_4_phyrexian_beast
g_3_3_elephant
g_3_3_frog_lizard
g_1_1_saproling g_1_1_saproling
g_1_1_snake g_1_1_snake
g_1_2_spider_reach g_1_2_spider_reach
g_2_2_bear
g_2_2_wolf g_2_2_wolf
ur_5_5_elemental_flying g_3_3_elephant
g_3_3_frog_lizard
g_4_4_phyrexian_beast
gu_1_1_snake gu_1_1_snake
wb_x_x_e_spirit_experience lightning_rager
r_3_1_elemental_shaman_haste
r_5_5_dragon_flying
u_2_2_drake_flying
ur_5_5_elemental_flying
w_2_2_cat
w_2_2_knight_first_strike
w_2_2_knight_vigilance
w_4_4_angel_flying
wb_1_1_spirit_flying wb_1_1_spirit_flying
wb_x_x_e_spirit_experience

View File

@@ -319,14 +319,14 @@ ScryfallCode=C17
309 L Forest @Kev Walker 309 L Forest @Kev Walker
[tokens] [tokens]
gold
c_0_1_eldrazi_spawn_sac
w_2_2_cat
b_1_1_bat_flying b_1_1_bat_flying
b_1_1_rat_deathtouch b_1_1_rat_deathtouch
b_1_1_vampire b_1_1_vampire
b_2_2_zombie b_2_2_zombie
brg_3_3_cat_dragon_flying
c_0_1_eldrazi_spawn_sac
c_a_gold_draw
g_2_2_cat_warrior_forestwalk
r_4_4_dragon_flying r_4_4_dragon_flying
r_6_6_dragon_flying r_6_6_dragon_flying
g_2_2_cat_warrior_forestwalk w_2_2_cat
brg_3_3_cat_dragon_flying

View File

@@ -8,4 +8,18 @@ ScryfallCode=HHO
[cards] [cards]
6 R Fruitcake Elemental @Darrell Riche 6 R Fruitcake Elemental @Darrell Riche
7 R Gifts Given @Jason Chan
8 R Evil Presents @Paul Bonner
9 R Season's Beatings @Kev Walker 9 R Season's Beatings @Kev Walker
10 R Snow Mercy @rk post
11 R Yule Ooze @Steve Prescott
12 R Naughty // Nice @Greg Staples
13 R Stocking Tiger @Terese Nielsen
14 M Mishra's Toy Workshop @Jung Park
15 M Goblin Sleigh Ride @Mark Zug
16 M Thopter Pie Network @Victor Adame Minguez
17 M Some Disassembly Required @Dmitry Burmak
18 M Bog Humbugs @Kieran Yanner
19 M Decorated Knight @Zoltan Boros
20 M Topdeck the Halls @Kieran Yanner
21 M Last-Minute Chopping @Marta Nael

View File

@@ -178,16 +178,16 @@ ScryfallCode=JOU
165 R Temple of Malady @James Paick 165 R Temple of Malady @James Paick
[tokens] [tokens]
gold b_x_x_zombie
w_1_1_soldier bg_1_1_e_snake_deathtouch
w_1_1_soldier c_a_gold_draw
w_1_1_soldier g_1_3_e_spider_reach
g_x_x_hydra
r_2_3_minotaur_haste
r_2_3_minotaur_haste
rg_2_2_satyr_haste
u_2_2_e_bird_flying u_2_2_e_bird_flying
u_4_4_sphinx_flying u_4_4_sphinx_flying
b_x_x_zombie w_1_1_soldier
r_2_3_minotaur_haste w_1_1_soldier
r_2_3_minotaur_haste w_1_1_soldier
g_x_x_hydra
g_1_3_e_spider_reach
rg_2_2_satyr_haste
bg_1_1_e_snake_deathtouch

View File

@@ -454,22 +454,22 @@ ScryfallCode=KHM
2 Woodland Chasm|KHM 2 Woodland Chasm|KHM
[tokens] [tokens]
w_4_4_angel_warrior_flying_vigilance
w_1_1_human_warrior
w_1_1_spirit_flying
u_1_1_bird_flying
u_4_4_giant_wizard
komas_coil
u_2_2_shapeshifter_changeling
b_2_2_zombie_berserker b_2_2_zombie_berserker
r_2_3_demon_berserker_menace c_a_treasure_sac
r_5_5_dragon_flying c_e_shard_draw
r_2_1_dwarf_berserker g_1_1_elf_warrior
g_2_2_bear g_2_2_bear
g_2_2_cat g_2_2_cat
g_1_1_elf_warrior
g_4_4_troll_warrior_trample g_4_4_troll_warrior_trample
c_a_treasure_sac
icy_manalith icy_manalith
komas_coil
r_2_1_dwarf_berserker
r_2_3_demon_berserker_menace
r_5_5_dragon_flying
replicated_ring replicated_ring
shard u_1_1_bird_flying
u_2_2_shapeshifter_changeling
u_4_4_giant_wizard
w_1_1_human_warrior
w_1_1_spirit_flying
w_4_4_angel_warrior_flying_vigilance

View File

@@ -184,6 +184,9 @@ ScryfallCode=SLD
203 R Commander's Sphere @Yosuke Ueno 203 R Commander's Sphere @Yosuke Ueno
204 R Darksteel Ingot @Theodoru 204 R Darksteel Ingot @Theodoru
205 R Gilded Lotus @Mab Graves 205 R Gilded Lotus @Mab Graves
206 R Exquisite Blood @Nils Hamm
207 R Night's Whisper @Tomas Duchek
208 R Phyrexian Tower @Nicholas Gregory
209 M Elesh Norn, Grand Cenobite @Igor Kieryluk 209 M Elesh Norn, Grand Cenobite @Igor Kieryluk
210 M Jin-Gitaxias, Core Augur @Eric Deschamps 210 M Jin-Gitaxias, Core Augur @Eric Deschamps
211 M Sheoldred, Whispering One @Jana Schirmer & Johannes Voss 211 M Sheoldred, Whispering One @Jana Schirmer & Johannes Voss
@@ -200,6 +203,11 @@ ScryfallCode=SLD
223 M Grave Titan @GodMachine 223 M Grave Titan @GodMachine
224 M Inferno Titan @Dibujante Nocturno 224 M Inferno Titan @Dibujante Nocturno
225 M Kroxa, Titan of Death's Hunger @DZO 225 M Kroxa, Titan of Death's Hunger @DZO
226 R Path to Exile @Marija Tiurina
227 R Well of Lost Dreams @Marija Tiurina
228 R Frantic Search @Marija Tiurina
229 R Intruder Alarm @Marija Tiurina
230 R Shelldock Isle @Marija Tiurina
231 R Gravecrawler @Fay Dalton 231 R Gravecrawler @Fay Dalton
232 M Liliana, Death's Majesty @Fay Dalton 232 M Liliana, Death's Majesty @Fay Dalton
233 M Rise of the Dark Realms @Fay Dalton 233 M Rise of the Dark Realms @Fay Dalton
@@ -270,6 +278,11 @@ ScryfallCode=SLD
302 R Vault of Whispers @DXTR 302 R Vault of Whispers @DXTR
303 R Great Furnace @DXTR 303 R Great Furnace @DXTR
304 R Tree of Tales @DXTR 304 R Tree of Tales @DXTR
305 R Ravenous Chupacabra @Crocodile Jackson
306 R Managorger Hydra @Crocodile Jackson
307 R Pathbreaker Ibex @Crocodile Jackson
308 R Temur Sabertooth @Crocodile Jackson
309 R Winding Constrictor @Crocodile Jackson
310 R Unbreakable Formation @Tyler Walpole 310 R Unbreakable Formation @Tyler Walpole
311 R Whir of Invention @Tyler Walpole 311 R Whir of Invention @Tyler Walpole
312 R Hero's Downfall @Tyler Walpole 312 R Hero's Downfall @Tyler Walpole
@@ -285,6 +298,16 @@ ScryfallCode=SLD
322 R Blasphemous Act @Martin Ansin 322 R Blasphemous Act @Martin Ansin
323 R Beast Within @Martin Ansin 323 R Beast Within @Martin Ansin
324 R Grafdigger's Cage @Martin Ansin 324 R Grafdigger's Cage @Martin Ansin
325 R Snow-Covered Plains @Jubilee
326 R Snow-Covered Island @Jubilee
327 R Snow-Covered Swamp @Jubilee
328 R Snow-Covered Mountain @Jubilee
329 R Snow-Covered Forest @Jubilee
330 R Aether Gust @Mateus Manhanini
331 R Counterspell @Mateus Manhanini
332 R Fabricate @Mateus Manhanini
333 R Fact or Fiction @Mateus Manhanini
334 R Mystical Tutor @Mateus Manhanini
340 M Mind Flayer, the Shadow @Isis 340 M Mind Flayer, the Shadow @Isis
341 R Chief Jim Hopper @Greg Staples 341 R Chief Jim Hopper @Greg Staples
342 R Dustin, Gadget Genius @Colin Boyer 342 R Dustin, Gadget Genius @Colin Boyer
@@ -303,6 +326,11 @@ ScryfallCode=SLD
356 R Slayers' Stronghold @Alayna Danner 356 R Slayers' Stronghold @Alayna Danner
357 R Gavony Township @Robbie Trevino 357 R Gavony Township @Robbie Trevino
358 R Alchemist's Refuge @DZO 358 R Alchemist's Refuge @DZO
359 R Plains @Donato Giancola
360 R Island @Yeong-Hao Han
361 R Swamp @Jonas De Ro
362 R Mountain @Grzegorz Rutkowski
363 R Forest @Andreas Rocha
364 R Swords to Plowshares @MSCHF 364 R Swords to Plowshares @MSCHF
365 R Grim Tutor @MSCHF 365 R Grim Tutor @MSCHF
366 R Blood Moon @MSCHF 366 R Blood Moon @MSCHF
@@ -318,15 +346,25 @@ ScryfallCode=SLD
376 M Craterhoof Behemoth @Kira 376 M Craterhoof Behemoth @Kira
377 R Metalwork Colossus @Chris Rahn 377 R Metalwork Colossus @Chris Rahn
378 R Metalwork Colossus @Hyan Tran 378 R Metalwork Colossus @Hyan Tran
379 R Zndrsplt, Eye of Wisdom @Alexis Ziritt
379b R Zndrsplt, Eye of Wisdom @Alexis Ziritt
380 R Okaun, Eye of Chaos @Alexis Ziritt
380b R Okaun, Eye of Chaos @Alexis Ziritt
381 R Propaganda @Scott Balmer
381b R Propaganda @Scott Balmer
382 R Stitch in Time @Micha Huigen
382b R Stitch in Time @Micha Huigen
383 R Krark's Thumb @Wooden Cyclops
383b R Krark's Thumb @Wooden Cyclops
477 R Path to Exile @Riot Games 477 R Path to Exile @Riot Games
478 R Rhystic Study @Riot Games 478 R Rhystic Study @Riot Games
482 R Counterflux @Riot Games 482 R Counterflux @Riot Games
483 R Thran Dynamo @Riot Games 483 R Thran Dynamo @Riot Games
484 L Plains @Riot Games 484 R Plains @Riot Games
485 L Island @Riot Games 485 R Island @Riot Games
486 L Swamp @Riot Games 486 R Swamp @Riot Games
487 L Mountain @Riot Games 487 R Mountain @Riot Games
488 L Forest @Riot Games 488 R Forest @Riot Games
501 R Karn, the Great Creator @Wisnu Tan 501 R Karn, the Great Creator @Wisnu Tan
502 R Ugin, the Ineffable @Daarken 502 R Ugin, the Ineffable @Daarken
503 M Gideon Blackblade @Kieran Yanner 503 M Gideon Blackblade @Kieran Yanner

View File

@@ -655,10 +655,11 @@ Unknown Shores|THB|1
[tokens] [tokens]
b_2_2_zombie b_2_2_zombie
c_0_4_a_wall_defender c_0_4_a_wall_defender
c_a_gold_draw
g_1_2_spider_reach g_1_2_spider_reach
g_2_2_wolf g_2_2_wolf
r_x_1_elemental_trample_haste
r_1_1_satyr_noblock r_1_1_satyr_noblock
r_x_1_elemental_trample_haste
u_1_1_tentacle u_1_1_tentacle
u_3_2_reflection u_3_2_reflection
u_8_8_kraken_hexproof u_8_8_kraken_hexproof
@@ -666,4 +667,3 @@ ub_2_3_nightmare_mill
w_0_1_goat w_0_1_goat
w_1_1_human_soldier w_1_1_human_soldier
w_2_2_pegasus_flying w_2_2_pegasus_flying
gold

View File

@@ -300,6 +300,7 @@ Curse
Rune Rune
Saga Saga
Shrine Shrine
Shard
[ArtifactTypes] [ArtifactTypes]
Blood Blood
Clue:Clues Clue:Clues

View File

@@ -1,4 +1,4 @@
Name:Phyrexian Germ Name:Phyrexian Germ Token
ManaCost:no cost ManaCost:no cost
Types:Creature Phyrexian Germ Types:Creature Phyrexian Germ
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Zombie Army Name:Zombie Army Token
ManaCost:no cost ManaCost:no cost
Types:Creature Zombie Army Types:Creature Zombie Army
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Cleric Name:Cleric Token
ManaCost:no cost ManaCost:no cost
Types:Creature Cleric Types:Creature Cleric
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Insect Name:Insect Token
ManaCost:no cost ManaCost:no cost
Types:Creature Insect Types:Creature Insect
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Serf Name:Serf Token
ManaCost:no cost ManaCost:no cost
Types:Creature Serf Types:Creature Serf
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Thrull Name:Thrull Token
ManaCost:no cost ManaCost:no cost
Types:Creature Thrull Types:Creature Thrull
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Assassin Name:Assassin Token
ManaCost:no cost ManaCost:no cost
Types:Creature Assassin Types:Creature Assassin
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Assassin Name:Assassin Token
ManaCost:no cost ManaCost:no cost
Types:Creature Assassin Types:Creature Assassin
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Assassin Name:Assassin Token
ManaCost:no cost ManaCost:no cost
Types:Creature Assassin Types:Creature Assassin
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Bat Name:Bat Token
ManaCost:no cost ManaCost:no cost
Types:Creature Bat Types:Creature Bat
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Faerie Rogue Name:Faerie Rogue Token
ManaCost:no cost ManaCost:no cost
Types:Creature Faerie Rogue Types:Creature Faerie Rogue
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Goblin Rogue Name:Goblin Rogue Token
ManaCost:no cost ManaCost:no cost
Types:Creature Goblin Rogue Types:Creature Goblin Rogue
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Harpy Name:Harpy Token
ManaCost:no cost ManaCost:no cost
Types:Creature Harpy Types:Creature Harpy
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Insect Name:Insect Token
ManaCost:no cost ManaCost:no cost
Types:Creature Insect Types:Creature Insect
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Minion Name:Minion Token
ManaCost:no cost ManaCost:no cost
Types:Creature Minion Types:Creature Minion
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Rat Name:Rat Token
ManaCost:no cost ManaCost:no cost
Types:Creature Rat Types:Creature Rat
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Rat Name:Rat Token
ManaCost:no cost ManaCost:no cost
Types:Creature Rat Types:Creature Rat
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Skeleton Name:Skeleton Token
ManaCost:no cost ManaCost:no cost
Types:Creature Skeleton Types:Creature Skeleton
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Skeleton Name:Skeleton Token
ManaCost:no cost ManaCost:no cost
Types:Creature Minion Types:Creature Minion
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Skeleton Name:Skeleton Token
ManaCost:no cost ManaCost:no cost
Colors:black Colors:black
Types:Creature Skeleton Types:Creature Skeleton

View File

@@ -1,4 +1,4 @@
Name:Slug Name:Slug Token
ManaCost:no cost ManaCost:no cost
Types:Creature Slug Types:Creature Slug
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Snake Name:Snake Token
ManaCost:no cost ManaCost:no cost
Types:Creature Snake Types:Creature Snake
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Thrull Name:Thrull Token
ManaCost:no cost ManaCost:no cost
Types:Creature Thrull Types:Creature Thrull
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Vampire Name:Vampire Token
ManaCost:no cost ManaCost:no cost
Types:Creature Vampire Types:Creature Vampire
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Vampire Knight Name:Vampire Knight Token
ManaCost:no cost ManaCost:no cost
Types:Creature Vampire Knight Types:Creature Vampire Knight
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Vampire Name:Vampire Token
ManaCost:no cost ManaCost:no cost
Types:Creature Vampire Types:Creature Vampire
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Wolf Name:Wolf Token
ManaCost:no cost ManaCost:no cost
Types:Creature Wolf Types:Creature Wolf
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Bat Name:Bat Token
ManaCost:no cost ManaCost:no cost
Types:Creature Bat Types:Creature Bat
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Cat Name:Cat Token
ManaCost:no cost ManaCost:no cost
Types:Creature Cat Types:Creature Cat
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Spider Name:Spider Token
ManaCost:no cost ManaCost:no cost
Types:Creature Spider Types:Creature Spider
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Warrior Name:Warrior Token
ManaCost:no cost ManaCost:no cost
Types:Creature Warrior Types:Creature Warrior
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Zombie Name:Zombie Token
ManaCost:no cost ManaCost:no cost
Types:Enchantment Creature Zombie Types:Enchantment Creature Zombie
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Knight Name:Knight Token
ManaCost:no cost ManaCost:no cost
Types:Creature Knight Types:Creature Knight
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Phyrexian Zombie Name:Phyrexian Zombie Token
ManaCost:no cost ManaCost:no cost
Types:Creature Phyrexian Zombie Types:Creature Phyrexian Zombie
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Pirate Name:Pirate Token
ManaCost:no cost ManaCost:no cost
Types:Creature Pirate Types:Creature Pirate
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Rogue Name:Rogue Token
ManaCost:no cost ManaCost:no cost
Types:Creature Rogue Types:Creature Rogue
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Rogue Name:Rogue Token
ManaCost:no cost ManaCost:no cost
Types:Creature Rogue Types:Creature Rogue
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Vampire Name:Vampire Token
ManaCost:no cost ManaCost:no cost
Types:Creature Vampire Types:Creature Vampire
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Zombie Name:Zombie Token
ManaCost:no cost ManaCost:no cost
Types:Creature Zombie Types:Creature Zombie
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Zombie Berserker Name:Zombie Berserker Token
ManaCost:no cost ManaCost:no cost
Types:Creature Zombie Berserker Types:Creature Zombie Berserker
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Zombie Name:Zombie Token
ManaCost:no cost ManaCost:no cost
Types:Creature Zombie Types:Creature Zombie
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Zombie Name:Zombie Token
ManaCost:no cost ManaCost:no cost
Types:Creature Zombie Types:Creature Zombie
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Zombie Knight Name:Zombie Knight Token
ManaCost:no cost ManaCost:no cost
Types:Creature Zombie Knight Types:Creature Zombie Knight
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Vampire Name:Vampire Token
ManaCost:no cost ManaCost:no cost
Types:Creature Vampire Types:Creature Vampire
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Spider Name:Spider Token
ManaCost:no cost ManaCost:no cost
Types:Creature Spider Types:Creature Spider
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Angel Name:Angel Token
ManaCost:no cost ManaCost:no cost
Types:Creature Angel Types:Creature Angel
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Beast Name:Beast Token
ManaCost:no cost ManaCost:no cost
Types:Creature Beast Types:Creature Beast
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Horror Name:Horror Token
ManaCost:no cost ManaCost:no cost
Types:Creature Horror Types:Creature Horror
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Horror Name:Horror Token
ManaCost:no cost ManaCost:no cost
Types:Creature Horror Types:Creature Horror
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Kavu Name:Kavu Token
ManaCost:no cost ManaCost:no cost
Types:Creature Kavu Types:Creature Kavu
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Horror Name:Horror Token
ManaCost:no cost ManaCost:no cost
Types:Creature Horror Types:Creature Horror
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Zombie Warrior Name:Zombie Warrior Token
ManaCost:no cost ManaCost:no cost
Types:Creature Zombie Warrior Types:Creature Zombie Warrior
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Demon Name:Demon Token
ManaCost:no cost ManaCost:no cost
Types:Creature Demon Types:Creature Demon
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Zombie Giant Name:Zombie Giant Token
ManaCost:no cost ManaCost:no cost
Types:Creature Zombie Giant Types:Creature Zombie Giant
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Demon Name:Demon Token
ManaCost:no cost ManaCost:no cost
Types:Creature Demon Types:Creature Demon
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Wurm Name:Wurm Token
ManaCost:no cost ManaCost:no cost
Types:Creature Wurm Types:Creature Wurm
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Aura Curse Name:Aura Curse Token
ManaCost:no cost ManaCost:no cost
Types:Enchantment Aura Curse Types:Enchantment Aura Curse
Colors:black Colors:black

View File

@@ -1,4 +1,4 @@
Name:Demon Name:Demon Token
ManaCost:no cost ManaCost:no cost
Colors:black Colors:black
Types:Creature Demon Types:Creature Demon

View File

@@ -1,4 +1,4 @@
Name:Horror Name:Horror Token
ManaCost:no cost ManaCost:no cost
Colors:black Colors:black
Types:Creature Horror Types:Creature Horror

View File

@@ -1,4 +1,4 @@
Name:Nightmare Horror Name:Nightmare Horror Token
ManaCost:no cost ManaCost:no cost
Colors:black Colors:black
Types:Creature Nightmare Horror Types:Creature Nightmare Horror

View File

@@ -1,4 +1,4 @@
Name:Phyrexian Minion Name:Phyrexian Minion Token
ManaCost:no cost ManaCost:no cost
Types:Creature Phyrexian Minion Types:Creature Phyrexian Minion
PT:*/* PT:*/*

View File

@@ -1,4 +1,4 @@
Name:Spirit Name:Spirit Token
ManaCost:no cost ManaCost:no cost
Colors:black Colors:black
Types:Creature Spirit Types:Creature Spirit

View File

@@ -1,4 +1,4 @@
Name:Vampire Name:Vampire Token
ManaCost:no cost ManaCost:no cost
Colors:black Colors:black
Types:Creature Vampire Types:Creature Vampire

View File

@@ -1,4 +1,4 @@
Name:Zombie Name:Zombie Token
ManaCost:no cost ManaCost:no cost
Colors:black Colors:black
Types:Creature Zombie Types:Creature Zombie

View File

@@ -1,4 +1,4 @@
Name:Zombie Horror Name:Zombie Horror Token
ManaCost:no cost ManaCost:no cost
Colors:black Colors:black
Types:Creature Zombie Horror Types:Creature Zombie Horror

View File

@@ -1,4 +1,4 @@
Name:Snake Name:Snake Token
ManaCost:no cost ManaCost:no cost
Types:Enchantment Creature Snake Types:Enchantment Creature Snake
Colors:black,green Colors:black,green

View File

@@ -1,4 +1,4 @@
Name:Insect Name:Insect Token
ManaCost:no cost ManaCost:no cost
Types:Creature Insect Types:Creature Insect
Colors:black,green Colors:black,green

View File

@@ -1,4 +1,4 @@
Name:Pest Name:Pest Token
ManaCost:no cost ManaCost:no cost
Types:Creature Pest Types:Creature Pest
Colors:black,green Colors:black,green

Some files were not shown because too many files have changed in this diff Show More