mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-14 17:58:01 +00:00
Merge branch 'master' of git.cardforge.org:core-developers/forge into agetian-master
This commit is contained in:
@@ -11,5 +11,6 @@ public class DifficultyData {
|
||||
public int staringMoney=10;
|
||||
public float enemyLifeFactor=1;
|
||||
public boolean startingDifficulty;
|
||||
public float sellFactor=0.2f;
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,83 +1,13 @@
|
||||
package forge.adventure.scene;
|
||||
|
||||
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.toolbox.FEvent;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* DeckEditScene
|
||||
* scene class that contains the Deck editor
|
||||
*/
|
||||
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;
|
||||
Stage stage;
|
||||
@@ -96,35 +26,14 @@ public class DeckEditScene extends ForgeScene {
|
||||
|
||||
@Override
|
||||
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();
|
||||
screen.getEditorType().getController().setDeck(deck);
|
||||
screen.refresh();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
super.enter();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FScreen getScreen() {
|
||||
return screen==null?screen = new AdventureDeckEditor():screen;
|
||||
return screen==null?screen = new AdventureDeckEditor(true):screen;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,9 +35,14 @@ public class InnScene extends UIScene {
|
||||
super.resLoaded();
|
||||
ui.onButtonPress("done",()->done());
|
||||
ui.onButtonPress("heal",()->heal());
|
||||
ui.onButtonPress("sell",()->sell());
|
||||
TextButton doneButton = ui.findActor("done");
|
||||
}
|
||||
|
||||
private void sell() {
|
||||
AdventureApplicationAdapter.instance.switchScene(SceneType.ShopScene.instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int keycode)
|
||||
{
|
||||
|
||||
@@ -14,7 +14,8 @@ public enum SceneType {
|
||||
TileMapScene(new forge.adventure.scene.TileMapScene()),
|
||||
RewardScene(new forge.adventure.scene.RewardScene()),
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,9 @@ import forge.adventure.util.*;
|
||||
import forge.deck.CardPool;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckSection;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.item.PaperCard;
|
||||
import forge.util.ItemPool;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@@ -43,6 +46,7 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
||||
return WorldSave.currentSave.getPlayer();
|
||||
}
|
||||
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) {
|
||||
|
||||
@@ -57,11 +61,13 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
||||
this.difficultyData.startingDifficulty=difficultyData.startingDifficulty;
|
||||
this.difficultyData.name=difficultyData.name;
|
||||
this.difficultyData.enemyLifeFactor=difficultyData.enemyLifeFactor;
|
||||
this.difficultyData.sellFactor=difficultyData.sellFactor;
|
||||
life=maxLife;
|
||||
avatarIndex = avatar;
|
||||
heroRace = race;
|
||||
isFemale = !male;
|
||||
name = n;
|
||||
newCards.clear();
|
||||
onGoldChangeList.emit();
|
||||
onLifeTotalChangeList.emit();
|
||||
}
|
||||
@@ -117,6 +123,9 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
||||
this.difficultyData.startingDifficulty=data.readBool("startingDifficulty");
|
||||
this.difficultyData.name=data.readString("difficultyName");
|
||||
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");
|
||||
@@ -155,6 +164,7 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
||||
cards.clear();
|
||||
cards.addAll(CardPool.fromCardList(Lists.newArrayList((String[])data.readObject("cards"))));
|
||||
|
||||
newCards.clear();
|
||||
onLifeTotalChangeList.emit();
|
||||
onGoldChangeList.emit();
|
||||
}
|
||||
@@ -169,6 +179,7 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
||||
data.store("startingDifficulty",this.difficultyData.startingDifficulty);
|
||||
data.store("difficultyName",this.difficultyData.name);
|
||||
data.store("enemyLifeFactor",this.difficultyData.enemyLifeFactor);
|
||||
data.store("sellFactor",this.difficultyData.sellFactor);
|
||||
|
||||
|
||||
data.store("name",name);
|
||||
@@ -220,6 +231,7 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
||||
{
|
||||
case Card:
|
||||
cards.add(reward.getCard());
|
||||
newCards.add(reward.getCard());
|
||||
break;
|
||||
case Gold:
|
||||
addGold(reward.getCount());
|
||||
@@ -297,4 +309,19 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
|
||||
deck = (Deck)deck.copyTo(text);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -737,7 +737,7 @@ public class AiController {
|
||||
}
|
||||
|
||||
int oldCMC = -1;
|
||||
boolean xCost = sa.getPayCosts().hasXInAnyCostPart() || sa.getHostCard().hasStartOfKeyword("Strive");
|
||||
boolean xCost = sa.costHasX() || sa.getHostCard().hasStartOfKeyword("Strive");
|
||||
if (!xCost) {
|
||||
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
|
||||
|
||||
@@ -722,7 +722,12 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
|
||||
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>() {
|
||||
@Override
|
||||
public boolean apply(String input) {
|
||||
|
||||
@@ -28,7 +28,6 @@ public class ImmediateTriggerEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
return "";
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5139,12 +5139,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
}
|
||||
|
||||
public final boolean hasABasicLandType() {
|
||||
for (final String type : getType().getSubtypes()) {
|
||||
if (forge.card.CardType.isABasicLandType(type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return Iterables.any(getType().getSubtypes(), CardType.Predicates.IS_BASIC_LAND_TYPE);
|
||||
}
|
||||
|
||||
public final boolean isUsedToPay() {
|
||||
|
||||
@@ -185,11 +185,9 @@ public class TokenInfo {
|
||||
}
|
||||
}
|
||||
if (!typeMap.isEmpty()) {
|
||||
String oldName = result.getName();
|
||||
|
||||
CardType type = new CardType(result.getType());
|
||||
String joinedName = StringUtils.join(type.getSubtypes(), " ");
|
||||
final boolean nameGenerated = oldName.equals(joinedName);
|
||||
final boolean nameGenerated = result.getName().endsWith(" Token");
|
||||
boolean typeChanged = false;
|
||||
|
||||
if (!Iterables.isEmpty(type.getSubtypes())) {
|
||||
@@ -207,7 +205,7 @@ public class TokenInfo {
|
||||
|
||||
// update generated Name
|
||||
if (nameGenerated) {
|
||||
result.setName(StringUtils.join(type.getSubtypes(), " "));
|
||||
result.setName(StringUtils.join(type.getSubtypes(), " ") + " Token");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public class GameSimulatorTest extends SimulationTestCase {
|
||||
assertEquals(1, heraldCopy.getToughnessBonusFromCounters());
|
||||
assertEquals(1, heraldCopy.getPowerBonusFromCounters());
|
||||
|
||||
Card warriorToken = findCardWithName(simGame, "Warrior");
|
||||
Card warriorToken = findCardWithName(simGame, "Warrior Token");
|
||||
assertNotNull(warriorToken);
|
||||
assertTrue(warriorToken.isSick());
|
||||
assertEquals(1, warriorToken.getCurrentPower());
|
||||
@@ -233,7 +233,7 @@ public class GameSimulatorTest extends SimulationTestCase {
|
||||
GameSimulator sim = createSimulator(game, p);
|
||||
sim.simulateSpellAbility(minusTwo);
|
||||
Game simGame = sim.getSimulatedGameState();
|
||||
Card vampireToken = findCardWithName(simGame, "Vampire");
|
||||
Card vampireToken = findCardWithName(simGame, "Vampire Token");
|
||||
assertNotNull(vampireToken);
|
||||
|
||||
Player simP = simGame.getPlayers().get(1);
|
||||
@@ -599,7 +599,7 @@ public class GameSimulatorTest extends SimulationTestCase {
|
||||
assertTrue(score > 0);
|
||||
Game simGame = sim.getSimulatedGameState();
|
||||
|
||||
Card scion = findCardWithName(simGame, "Eldrazi Scion");
|
||||
Card scion = findCardWithName(simGame, "Eldrazi Scion Token");
|
||||
assertNotNull(scion);
|
||||
assertEquals(1, scion.getNetPower());
|
||||
assertEquals(1, scion.getNetToughness());
|
||||
@@ -608,7 +608,7 @@ public class GameSimulatorTest extends SimulationTestCase {
|
||||
|
||||
GameCopier copier = new GameCopier(simGame);
|
||||
Game copy = copier.makeCopy();
|
||||
Card scionCopy = findCardWithName(copy, "Eldrazi Scion");
|
||||
Card scionCopy = findCardWithName(copy, "Eldrazi Scion Token");
|
||||
assertNotNull(scionCopy);
|
||||
assertEquals(1, scionCopy.getNetPower());
|
||||
assertEquals(1, scionCopy.getNetToughness());
|
||||
@@ -1288,7 +1288,7 @@ public class GameSimulatorTest extends SimulationTestCase {
|
||||
assertTrue(score > 0);
|
||||
Game simGame = sim.getSimulatedGameState();
|
||||
|
||||
int numZombies = countCardsWithName(simGame, "Zombie");
|
||||
int numZombies = countCardsWithName(simGame, "Zombie Token");
|
||||
assertEquals(2, numZombies);
|
||||
}
|
||||
|
||||
@@ -1323,11 +1323,11 @@ public class GameSimulatorTest extends SimulationTestCase {
|
||||
GameSimulator sim = createSimulator(game, p);
|
||||
int score = sim.simulateSpellAbility(fatalPushSA).value;
|
||||
assertTrue(score > 0);
|
||||
assertEquals(2, countCardsWithName(sim.getSimulatedGameState(), "Zombie"));
|
||||
assertEquals(2, countCardsWithName(sim.getSimulatedGameState(), "Zombie Token"));
|
||||
|
||||
score = sim.simulateSpellAbility(electrifySA).value;
|
||||
assertTrue(score > 0);
|
||||
assertEquals(countCardsWithName(sim.getSimulatedGameState(), "Zombie"), 4);
|
||||
assertEquals(4, countCardsWithName(sim.getSimulatedGameState(), "Zombie Token"));
|
||||
}
|
||||
|
||||
public void testPlayerXCount() {
|
||||
@@ -1564,7 +1564,7 @@ public class GameSimulatorTest extends SimulationTestCase {
|
||||
assertTrue(score > 0);
|
||||
Game simGame = sim.getSimulatedGameState();
|
||||
|
||||
int numZombies = countCardsWithName(simGame, "Zombie");
|
||||
int numZombies = countCardsWithName(simGame, "Zombie Token");
|
||||
assertEquals(4, numZombies);
|
||||
}
|
||||
|
||||
@@ -1592,7 +1592,7 @@ public class GameSimulatorTest extends SimulationTestCase {
|
||||
assertTrue(score > 0);
|
||||
Game simGame = sim.getSimulatedGameState();
|
||||
|
||||
int numZombies = countCardsWithName(simGame, "Zombie");
|
||||
int numZombies = countCardsWithName(simGame, "Zombie Token");
|
||||
assertEquals(3, numZombies);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}));
|
||||
addItem(new FMenuItem(localizer.getMessage("lblSaveAs"), Forge.hdbuttons ? FSkinImage.HDSAVEAS : FSkinImage.SAVEAS, new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
String defaultName = editorType.getController().getNextAvailableName();
|
||||
FOptionPane.showInputDialog(localizer.getMessage("lblNameNewCopyDeck"), defaultName, new Callback<String>() {
|
||||
@Override
|
||||
public void run(String result) {
|
||||
if (!StringUtils.isEmpty(result)) {
|
||||
editorType.getController().saveAs(result);
|
||||
if(allowsSave())
|
||||
addItem(new FMenuItem(localizer.getMessage("lblSaveAs"), Forge.hdbuttons ? FSkinImage.HDSAVEAS : FSkinImage.SAVEAS, new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
String defaultName = editorType.getController().getNextAvailableName();
|
||||
FOptionPane.showInputDialog(localizer.getMessage("lblNameNewCopyDeck"), defaultName, new Callback<String>() {
|
||||
@Override
|
||||
public void run(String result) {
|
||||
if (!StringUtils.isEmpty(result)) {
|
||||
editorType.getController().saveAs(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
}));
|
||||
}
|
||||
if (allowRename()) {
|
||||
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() {
|
||||
cardManager.setup(config, parentScreen.getColOverrides(config));
|
||||
cardManager.setup(config);
|
||||
}
|
||||
|
||||
protected boolean canAddCards() {
|
||||
@@ -1256,6 +1257,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
addCommanderItems(menu, card, true, true);
|
||||
|
||||
if (parentScreen.getEditorType() == EditorType.Constructed) {
|
||||
|
||||
@@ -19,18 +19,21 @@
|
||||
"name":"Easy",
|
||||
"startingLife":16,
|
||||
"staringMoney":200,
|
||||
"enemyLifeFactor":0.8
|
||||
"enemyLifeFactor":0.8 ,
|
||||
"sellFactor":0.5
|
||||
},{
|
||||
"name":"Normal",
|
||||
"startingLife":12,
|
||||
"staringMoney":100,
|
||||
"startingDifficulty":true,
|
||||
"enemyLifeFactor":1.0
|
||||
"enemyLifeFactor":1.0 ,
|
||||
"sellFactor":0.2
|
||||
},{
|
||||
"name":"Hard",
|
||||
"startingLife":8,
|
||||
"staringMoney":10,
|
||||
"enemyLifeFactor":1.5
|
||||
"enemyLifeFactor":1.5 ,
|
||||
"sellFactor":0.1
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -20,6 +20,15 @@
|
||||
"x": 420,
|
||||
"y": 10
|
||||
} ,
|
||||
{
|
||||
"type" : "TextButton",
|
||||
"name" : "sell" ,
|
||||
"text" : "Sell cards" ,
|
||||
"width": 48,
|
||||
"height": 16,
|
||||
"x": 420,
|
||||
"y": 34
|
||||
} ,
|
||||
{
|
||||
"type" : "TextButton",
|
||||
"name" : "done" ,
|
||||
@@ -27,7 +36,7 @@
|
||||
"width": 48,
|
||||
"height": 16,
|
||||
"x": 420,
|
||||
"y": 34
|
||||
"y": 58
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@@ -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$ 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: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: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: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: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 | 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:X:Remembered$CardManaCost
|
||||
SVar:X:TriggerRemembered$CardManaCost
|
||||
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.
|
||||
|
||||
@@ -5,5 +5,5 @@ K:Enchant player
|
||||
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.")
|
||||
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.")
|
||||
|
||||
@@ -2,5 +2,5 @@ Name:Gild
|
||||
ManaCost:3 B
|
||||
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.")
|
||||
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.")
|
||||
|
||||
@@ -2,11 +2,14 @@ Name:Goblin Welder
|
||||
ManaCost:R
|
||||
Types:Creature Goblin Artificer
|
||||
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
|
||||
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:DBSacrifice:DB$ SacrificeAll | ValidCards$ Card.IsRemembered | ConditionDefined$ Remembered | ConditionPresent$ Artifact | ConditionCompare$ GE1 | ConditionCheckSVar$ CheckImprint | ConditionSVarCompare$ GE1 | SubAbility$ DBReturn | StackDescription$ None
|
||||
SVar:DBReturn:DB$ ChangeZone | Defined$ Imprinted | Origin$ Graveyard | Destination$ Battlefield | SubAbility$ DBCleanup | ConditionDefined$ Remembered | ConditionPresent$ Artifact | ConditionCompare$ GE1 | ConditionCheckSVar$ CheckImprint | ConditionSVarCompare$ GE1 | 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 | 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:DBBranch:DB$ Branch | BranchConditionSVar$ TargetCheck | BranchConditionSVarCompare$ GE2 | TrueSubAbility$ DBSacrifice | FalseSubAbility$ DBCleanup
|
||||
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:TargetCheck:SVar$CheckRemem/Plus.CheckImprint
|
||||
SVar:CheckRemem:Remembered$Valid Artifact.sharesControllerWith Imprinted
|
||||
SVar:CheckImprint:Imprinted$Valid Artifact.sharesControllerWith Remembered
|
||||
AI:RemoveDeck:All
|
||||
AI:RemoveDeck:Random
|
||||
|
||||
@@ -4,7 +4,7 @@ Types:Legendary Creature Human Noble
|
||||
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.")
|
||||
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: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.")
|
||||
|
||||
@@ -3,7 +3,7 @@ ManaCost:X W U U
|
||||
Types:Legendary Planeswalker Niko
|
||||
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.")
|
||||
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
|
||||
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
|
||||
@@ -11,6 +11,6 @@ SVar:Trig:Mode$ DamageDealtOnce | ValidSource$ Creature.IsRemembered | Execute$
|
||||
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.
|
||||
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
|
||||
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.
|
||||
|
||||
@@ -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: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: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
|
||||
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.")
|
||||
|
||||
@@ -178,14 +178,14 @@ ScryfallCode=BNG
|
||||
165 R Temple of Plenty @Noah Bradley
|
||||
|
||||
[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_cat_soldier_vigilance
|
||||
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
|
||||
|
||||
@@ -352,27 +352,27 @@ ScryfallCode=C15
|
||||
342 L Forest @Jonas De Ro
|
||||
|
||||
[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_2_2_zombie
|
||||
r_5_5_dragon_flying
|
||||
r_3_1_elemental_shaman_haste
|
||||
g_2_2_bear
|
||||
g_4_4_phyrexian_beast
|
||||
g_3_3_elephant
|
||||
g_3_3_frog_lizard
|
||||
c_1_1_shapeshifter_changeling
|
||||
c_a_gold_draw
|
||||
g_1_1_saproling
|
||||
g_1_1_snake
|
||||
g_1_2_spider_reach
|
||||
g_2_2_bear
|
||||
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
|
||||
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_x_x_e_spirit_experience
|
||||
|
||||
@@ -319,14 +319,14 @@ ScryfallCode=C17
|
||||
309 L Forest @Kev Walker
|
||||
|
||||
[tokens]
|
||||
gold
|
||||
c_0_1_eldrazi_spawn_sac
|
||||
w_2_2_cat
|
||||
b_1_1_bat_flying
|
||||
b_1_1_rat_deathtouch
|
||||
b_1_1_vampire
|
||||
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_6_6_dragon_flying
|
||||
g_2_2_cat_warrior_forestwalk
|
||||
brg_3_3_cat_dragon_flying
|
||||
w_2_2_cat
|
||||
|
||||
@@ -8,4 +8,18 @@ ScryfallCode=HHO
|
||||
|
||||
[cards]
|
||||
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
|
||||
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
|
||||
|
||||
@@ -178,16 +178,16 @@ ScryfallCode=JOU
|
||||
165 R Temple of Malady @James Paick
|
||||
|
||||
[tokens]
|
||||
gold
|
||||
w_1_1_soldier
|
||||
w_1_1_soldier
|
||||
w_1_1_soldier
|
||||
b_x_x_zombie
|
||||
bg_1_1_e_snake_deathtouch
|
||||
c_a_gold_draw
|
||||
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_4_4_sphinx_flying
|
||||
b_x_x_zombie
|
||||
r_2_3_minotaur_haste
|
||||
r_2_3_minotaur_haste
|
||||
g_x_x_hydra
|
||||
g_1_3_e_spider_reach
|
||||
rg_2_2_satyr_haste
|
||||
bg_1_1_e_snake_deathtouch
|
||||
w_1_1_soldier
|
||||
w_1_1_soldier
|
||||
w_1_1_soldier
|
||||
|
||||
@@ -454,22 +454,22 @@ ScryfallCode=KHM
|
||||
2 Woodland Chasm|KHM
|
||||
|
||||
[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
|
||||
r_2_3_demon_berserker_menace
|
||||
r_5_5_dragon_flying
|
||||
r_2_1_dwarf_berserker
|
||||
c_a_treasure_sac
|
||||
c_e_shard_draw
|
||||
g_1_1_elf_warrior
|
||||
g_2_2_bear
|
||||
g_2_2_cat
|
||||
g_1_1_elf_warrior
|
||||
g_4_4_troll_warrior_trample
|
||||
c_a_treasure_sac
|
||||
icy_manalith
|
||||
komas_coil
|
||||
r_2_1_dwarf_berserker
|
||||
r_2_3_demon_berserker_menace
|
||||
r_5_5_dragon_flying
|
||||
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
|
||||
|
||||
@@ -184,6 +184,9 @@ ScryfallCode=SLD
|
||||
203 R Commander's Sphere @Yosuke Ueno
|
||||
204 R Darksteel Ingot @Theodoru
|
||||
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
|
||||
210 M Jin-Gitaxias, Core Augur @Eric Deschamps
|
||||
211 M Sheoldred, Whispering One @Jana Schirmer & Johannes Voss
|
||||
@@ -200,6 +203,11 @@ ScryfallCode=SLD
|
||||
223 M Grave Titan @GodMachine
|
||||
224 M Inferno Titan @Dibujante Nocturno
|
||||
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
|
||||
232 M Liliana, Death's Majesty @Fay Dalton
|
||||
233 M Rise of the Dark Realms @Fay Dalton
|
||||
@@ -270,6 +278,11 @@ ScryfallCode=SLD
|
||||
302 R Vault of Whispers @DXTR
|
||||
303 R Great Furnace @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
|
||||
311 R Whir of Invention @Tyler Walpole
|
||||
312 R Hero's Downfall @Tyler Walpole
|
||||
@@ -285,6 +298,16 @@ ScryfallCode=SLD
|
||||
322 R Blasphemous Act @Martin Ansin
|
||||
323 R Beast Within @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
|
||||
341 R Chief Jim Hopper @Greg Staples
|
||||
342 R Dustin, Gadget Genius @Colin Boyer
|
||||
@@ -303,6 +326,11 @@ ScryfallCode=SLD
|
||||
356 R Slayers' Stronghold @Alayna Danner
|
||||
357 R Gavony Township @Robbie Trevino
|
||||
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
|
||||
365 R Grim Tutor @MSCHF
|
||||
366 R Blood Moon @MSCHF
|
||||
@@ -318,15 +346,25 @@ ScryfallCode=SLD
|
||||
376 M Craterhoof Behemoth @Kira
|
||||
377 R Metalwork Colossus @Chris Rahn
|
||||
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
|
||||
478 R Rhystic Study @Riot Games
|
||||
482 R Counterflux @Riot Games
|
||||
483 R Thran Dynamo @Riot Games
|
||||
484 L Plains @Riot Games
|
||||
485 L Island @Riot Games
|
||||
486 L Swamp @Riot Games
|
||||
487 L Mountain @Riot Games
|
||||
488 L Forest @Riot Games
|
||||
484 R Plains @Riot Games
|
||||
485 R Island @Riot Games
|
||||
486 R Swamp @Riot Games
|
||||
487 R Mountain @Riot Games
|
||||
488 R Forest @Riot Games
|
||||
501 R Karn, the Great Creator @Wisnu Tan
|
||||
502 R Ugin, the Ineffable @Daarken
|
||||
503 M Gideon Blackblade @Kieran Yanner
|
||||
|
||||
@@ -655,10 +655,11 @@ Unknown Shores|THB|1
|
||||
[tokens]
|
||||
b_2_2_zombie
|
||||
c_0_4_a_wall_defender
|
||||
c_a_gold_draw
|
||||
g_1_2_spider_reach
|
||||
g_2_2_wolf
|
||||
r_x_1_elemental_trample_haste
|
||||
r_1_1_satyr_noblock
|
||||
r_x_1_elemental_trample_haste
|
||||
u_1_1_tentacle
|
||||
u_3_2_reflection
|
||||
u_8_8_kraken_hexproof
|
||||
@@ -666,4 +667,3 @@ ub_2_3_nightmare_mill
|
||||
w_0_1_goat
|
||||
w_1_1_human_soldier
|
||||
w_2_2_pegasus_flying
|
||||
gold
|
||||
|
||||
@@ -300,6 +300,7 @@ Curse
|
||||
Rune
|
||||
Saga
|
||||
Shrine
|
||||
Shard
|
||||
[ArtifactTypes]
|
||||
Blood
|
||||
Clue:Clues
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Phyrexian Germ
|
||||
Name:Phyrexian Germ Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Phyrexian Germ
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Zombie Army
|
||||
Name:Zombie Army Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Zombie Army
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Cleric
|
||||
Name:Cleric Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Cleric
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Insect
|
||||
Name:Insect Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Insect
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Serf
|
||||
Name:Serf Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Serf
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Thrull
|
||||
Name:Thrull Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Thrull
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Assassin
|
||||
Name:Assassin Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Assassin
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Assassin
|
||||
Name:Assassin Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Assassin
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Assassin
|
||||
Name:Assassin Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Assassin
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Bat
|
||||
Name:Bat Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Bat
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Faerie Rogue
|
||||
Name:Faerie Rogue Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Faerie Rogue
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Goblin Rogue
|
||||
Name:Goblin Rogue Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Goblin Rogue
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Harpy
|
||||
Name:Harpy Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Harpy
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Insect
|
||||
Name:Insect Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Insect
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Minion
|
||||
Name:Minion Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Minion
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Rat
|
||||
Name:Rat Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Rat
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Rat
|
||||
Name:Rat Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Rat
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Skeleton
|
||||
Name:Skeleton Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Skeleton
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Skeleton
|
||||
Name:Skeleton Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Minion
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Skeleton
|
||||
Name:Skeleton Token
|
||||
ManaCost:no cost
|
||||
Colors:black
|
||||
Types:Creature Skeleton
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Slug
|
||||
Name:Slug Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Slug
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Snake
|
||||
Name:Snake Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Snake
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Thrull
|
||||
Name:Thrull Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Thrull
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Vampire
|
||||
Name:Vampire Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Vampire
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Vampire Knight
|
||||
Name:Vampire Knight Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Vampire Knight
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Vampire
|
||||
Name:Vampire Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Vampire
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Wolf
|
||||
Name:Wolf Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Wolf
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Bat
|
||||
Name:Bat Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Bat
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Cat
|
||||
Name:Cat Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Cat
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Spider
|
||||
Name:Spider Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Spider
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Warrior
|
||||
Name:Warrior Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Warrior
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Zombie
|
||||
Name:Zombie Token
|
||||
ManaCost:no cost
|
||||
Types:Enchantment Creature Zombie
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Knight
|
||||
Name:Knight Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Knight
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Phyrexian Zombie
|
||||
Name:Phyrexian Zombie Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Phyrexian Zombie
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Pirate
|
||||
Name:Pirate Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Pirate
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Rogue
|
||||
Name:Rogue Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Rogue
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Rogue
|
||||
Name:Rogue Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Rogue
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Vampire
|
||||
Name:Vampire Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Vampire
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Zombie
|
||||
Name:Zombie Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Zombie
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Zombie Berserker
|
||||
Name:Zombie Berserker Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Zombie Berserker
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Zombie
|
||||
Name:Zombie Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Zombie
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Zombie
|
||||
Name:Zombie Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Zombie
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Zombie Knight
|
||||
Name:Zombie Knight Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Zombie Knight
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Vampire
|
||||
Name:Vampire Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Vampire
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Spider
|
||||
Name:Spider Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Spider
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Angel
|
||||
Name:Angel Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Angel
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Beast
|
||||
Name:Beast Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Beast
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Horror
|
||||
Name:Horror Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Horror
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Horror
|
||||
Name:Horror Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Horror
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Kavu
|
||||
Name:Kavu Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Kavu
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Horror
|
||||
Name:Horror Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Horror
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Zombie Warrior
|
||||
Name:Zombie Warrior Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Zombie Warrior
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Demon
|
||||
Name:Demon Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Demon
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Zombie Giant
|
||||
Name:Zombie Giant Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Zombie Giant
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Demon
|
||||
Name:Demon Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Demon
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Wurm
|
||||
Name:Wurm Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Wurm
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Aura Curse
|
||||
Name:Aura Curse Token
|
||||
ManaCost:no cost
|
||||
Types:Enchantment Aura Curse
|
||||
Colors:black
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Demon
|
||||
Name:Demon Token
|
||||
ManaCost:no cost
|
||||
Colors:black
|
||||
Types:Creature Demon
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Horror
|
||||
Name:Horror Token
|
||||
ManaCost:no cost
|
||||
Colors:black
|
||||
Types:Creature Horror
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Nightmare Horror
|
||||
Name:Nightmare Horror Token
|
||||
ManaCost:no cost
|
||||
Colors:black
|
||||
Types:Creature Nightmare Horror
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Phyrexian Minion
|
||||
Name:Phyrexian Minion Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Phyrexian Minion
|
||||
PT:*/*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Spirit
|
||||
Name:Spirit Token
|
||||
ManaCost:no cost
|
||||
Colors:black
|
||||
Types:Creature Spirit
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Vampire
|
||||
Name:Vampire Token
|
||||
ManaCost:no cost
|
||||
Colors:black
|
||||
Types:Creature Vampire
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Zombie
|
||||
Name:Zombie Token
|
||||
ManaCost:no cost
|
||||
Colors:black
|
||||
Types:Creature Zombie
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Zombie Horror
|
||||
Name:Zombie Horror Token
|
||||
ManaCost:no cost
|
||||
Colors:black
|
||||
Types:Creature Zombie Horror
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Snake
|
||||
Name:Snake Token
|
||||
ManaCost:no cost
|
||||
Types:Enchantment Creature Snake
|
||||
Colors:black,green
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Insect
|
||||
Name:Insect Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Insect
|
||||
Colors:black,green
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Name:Pest
|
||||
Name:Pest Token
|
||||
ManaCost:no cost
|
||||
Types:Creature Pest
|
||||
Colors:black,green
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user