From b2b46176c7377286d5949ca1a4817e2daa865617 Mon Sep 17 00:00:00 2001 From: friarsol Date: Thu, 3 Dec 2020 22:32:45 -0500 Subject: [PATCH 01/97] Handle new edition print sheets properly --- forge-gui/tools/EditionTracking.py | 44 +++++++++++++++++++----------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/forge-gui/tools/EditionTracking.py b/forge-gui/tools/EditionTracking.py index 4156807e0d1..8963985a87e 100644 --- a/forge-gui/tools/EditionTracking.py +++ b/forge-gui/tools/EditionTracking.py @@ -4,6 +4,7 @@ import json import os,sys,fnmatch,re import requests +import pdb toolsDir = os.path.abspath(os.path.dirname( __file__ )) resDir = os.path.abspath(os.path.join(toolsDir, '..', 'res')) @@ -13,6 +14,8 @@ allJsonUrl = 'http://mtgjson.com/json/AllCards.json' def initializeEditions(): ignoredTypes = [ "From_the_Vault", "Duel_Decks", "Online", "Premium_Deck_Series" ] + editionSections = [ "[cards]", "[precon product]", "[borderless]", "[showcase]", "[extended art]", "[buy a box]", "[promo]" ] + print("Parsing Editions folder") for root, dirnames, filenames in os.walk(editionsDir): for fileName in fnmatch.filter(filenames, '*.txt'): @@ -23,10 +26,11 @@ def initializeEditions(): metadata = True setcode = setname = settype = None for line in currentEdition.readlines(): + line = line.strip() if metadata: - if line.startswith("[cards]"): + if line in editionSections: metadata = False - if setcode: + if setcode and setcode not in setCodes: setCodes.append(setcode) setCodeToName[setcode] = setname if settype in ignoredTypes: @@ -42,24 +46,29 @@ def initializeEditions(): settype = line.split("=")[1].rstrip() else: - if line.startswith("[tokens]"): - # Hopefully tokens are last in the print sheet ordering - metadata = True + if not line: continue - if line.startswith("#") or line.startswith("["): + if line.startswith("["): + if line not in editionSections: + metadata = True continue - if line: - hasSetNumbers = line[0].isdigit() + if line.startswith("#"): + continue - card = line.split(" ", 2 if hasSetNumbers else 1)[-1].rstrip() - if card not in mtgDataCards: - #print card - mtgDataCards[card] = [setcode] + hasSetNumbers = line[0].isdigit() + card = line.split(" ", 2 if hasSetNumbers else 1)[-1].rstrip().split('|')[0] - else: - mtgDataCards[card].append(setcode) + if card.endswith('+'): + card = card[:-1] + + if card not in mtgDataCards: + #print card + mtgDataCards[card] = [setcode] + + else: + mtgDataCards[card].append(setcode) print "Total Cards Found in all editions", len(mtgDataCards) print "These sets will be ignored in some output files", ignoredSet @@ -90,7 +99,7 @@ def initializeOracleText(): return oracleDict def normalizeOracle(oracle): - return oracle.replace(u'\u2014', '-').replace(u'\u2212', '-').replace(u'\u2018', "'").replace(u'\u201c', '"').replace(u'\u201d', '"').replace(u'\u2022', '-').replace(u'\xc6', 'AE').replace(u'\xf6', 'o') + return oracle.replace(u'\u2014', '-').replace(u'\u2212', '-').replace(u'\u2018', "'").replace(u'\u201c', '"').replace(u'\u201d', '"').replace(u'\u2022', '-').replace(u'\xc6', 'AE').replace(u'\xf6', 'o').replace(u'\xb2', '^2').replace(u'\xae', '(R)').replace(u'\u221e', 'INF') def initializeForgeCards(): @@ -347,7 +356,10 @@ if __name__ == '__main__': except: text = '' - output.write(text + '\n\n') + try: + output.write(text + '\n\n') + except: + print everyMissing output.write("\n") output.write("Total: " + str(total) + "\n") output.write("Percentage implemented: " + str(round(percentage,2)) + "%\n") From 6df146d313f1ad0769efbc38c901a50fd3a606f7 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Fri, 4 Dec 2020 12:49:15 +0800 Subject: [PATCH 02/97] update Quest Commander mode --- forge-gui-mobile/src/forge/screens/home/HomeScreen.java | 9 +++++++++ forge-gui-mobile/src/forge/screens/quest/QuestMenu.java | 9 ++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/forge-gui-mobile/src/forge/screens/home/HomeScreen.java b/forge-gui-mobile/src/forge/screens/home/HomeScreen.java index 6c124ff90a7..dfee6c70139 100644 --- a/forge-gui-mobile/src/forge/screens/home/HomeScreen.java +++ b/forge-gui-mobile/src/forge/screens/home/HomeScreen.java @@ -37,6 +37,7 @@ public class HomeScreen extends FScreen { private final List buttons = new ArrayList<>(); private int activeButtonIndex, baseButtonCount; private FDeckChooser deckManager; + private boolean QuestCommander = false; private HomeScreen() { super((Header)null); @@ -104,6 +105,14 @@ public class HomeScreen extends FScreen { buttons.add(buttonScroller.add(new MenuButton(caption, command))); } + public void updateQuestCommanderMode(boolean isCommander){ + QuestCommander = isCommander; + } + + public boolean getQuestCommanderMode() { + return QuestCommander; + } + public void addButtonForMode(String caption, final FEventHandler command) { //ensure we don't add the same mode button more than once for (int i = baseButtonCount; i < buttons.size(); i++) { diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java b/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java index 5723234b19c..43bb8e9b21d 100644 --- a/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java +++ b/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java @@ -163,7 +163,7 @@ public class QuestMenu extends FPopupMenu implements IVQuestStats { HomeScreen.instance.addButtonForMode(Localizer.getInstance().getMessage("lblQuestMode"), new FEventHandler() { @Override public void handleEvent(FEvent e) { - launchQuestMode(LaunchReason.StartQuestMode); + launchQuestMode(LaunchReason.StartQuestMode, HomeScreen.instance.getQuestCommanderMode()); } }); } @@ -182,10 +182,8 @@ public class QuestMenu extends FPopupMenu implements IVQuestStats { NewQuest } - public static void launchQuestMode(final LaunchReason reason) { - launchQuestMode(reason, false); - } public static void launchQuestMode(final LaunchReason reason, boolean commanderMode) { + HomeScreen.instance.updateQuestCommanderMode(commanderMode); decksScreen.commanderMode = commanderMode; //attempt to load current quest final File dirQuests = new File(ForgeConstants.QUEST_SAVE_DIR); @@ -248,7 +246,8 @@ public class QuestMenu extends FPopupMenu implements IVQuestStats { addItem(spellShopItem); spellShopItem.setSelected(currentScreen == spellShopScreen); addItem(bazaarItem); bazaarItem.setSelected(currentScreen == bazaarScreen); addItem(unlockSetsItem); - addItem(travelItem); + if(!HomeScreen.instance.getQuestCommanderMode()) + addItem(travelItem); addItem(statsItem); statsItem.setSelected(currentScreen == statsScreen); addItem(prefsItem); prefsItem.setSelected(currentScreen == prefsScreen); } From 6935adc39f4d4805e26a303b00eb83ab1ba5facd Mon Sep 17 00:00:00 2001 From: Northmoc Date: Fri, 4 Dec 2020 14:28:39 -0500 Subject: [PATCH 03/97] fix rockslide_sorcerer.txt type --- forge-gui/res/cardsfolder/r/rockslide_sorcerer.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge-gui/res/cardsfolder/r/rockslide_sorcerer.txt b/forge-gui/res/cardsfolder/r/rockslide_sorcerer.txt index 1aa627b48fc..a4893deb9f7 100755 --- a/forge-gui/res/cardsfolder/r/rockslide_sorcerer.txt +++ b/forge-gui/res/cardsfolder/r/rockslide_sorcerer.txt @@ -1,6 +1,6 @@ Name:Rockslide Sorcerer ManaCost:3 R -Types:Creature Human Warrior +Types:Creature Human Wizard PT:3/3 T:Mode$ SpellCast | ValidCard$ Instant,Sorcery,Wizard | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigDealDamage | TriggerDescription$ Whenever you cast an instant, sorcery, or Wizard spell, CARDNAME deals 1 damage to any target. SVar:TrigDealDamage:DB$ DealDamage | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ 1 From c3f60b47647dbe02d2ff3f67f322e9c1ba1bcafd Mon Sep 17 00:00:00 2001 From: Northmoc Date: Fri, 4 Dec 2020 14:44:32 -0500 Subject: [PATCH 04/97] fix Statics that care about if you're the Monarch --- .../src/main/java/forge/game/staticability/StaticAbility.java | 1 + forge-gui/res/cardsfolder/e/entourage_of_trest.txt | 2 +- forge-gui/res/cardsfolder/upcoming/archon_of_coronation.txt | 2 +- forge-gui/res/cardsfolder/upcoming/dawnblade_regent.txt | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java index bfb2ac6f552..8f2d8987037 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java @@ -582,6 +582,7 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone if (condition.equals("Ferocious") && !controller.hasFerocious()) return false; if (condition.equals("Desert") && !controller.hasDesert()) return false; if (condition.equals("Blessing") && !controller.hasBlessing()) return false; + if (condition.equals("Monarch") & !controller.isMonarch()) return false; if (condition.equals("PlayerTurn")) { if (!ph.isPlayerTurn(controller)) { diff --git a/forge-gui/res/cardsfolder/e/entourage_of_trest.txt b/forge-gui/res/cardsfolder/e/entourage_of_trest.txt index 8b0c23ee88b..7f8ea4dca78 100644 --- a/forge-gui/res/cardsfolder/e/entourage_of_trest.txt +++ b/forge-gui/res/cardsfolder/e/entourage_of_trest.txt @@ -4,6 +4,6 @@ Types:Creature Elf Soldier PT:4/4 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMonarch | TriggerDescription$ When CARDNAME enters the battlefield, you become the monarch. SVar:TrigMonarch:DB$ BecomeMonarch | Defined$ You -S:Mode$ Continuous | Affected$ Card.Self | Condition$ You.isMonarch | CanBlockAmount$ 1 | Description$ CARDNAME can block an additional creature each combat as long as you're the monarch. +S:Mode$ Continuous | Affected$ Card.Self | Condition$ Monarch | CanBlockAmount$ 1 | Description$ CARDNAME can block an additional creature each combat as long as you're the monarch. SVar:Picture:http://www.wizards.com/global/images/magic/general/entourage_of_trest.jpg Oracle:When Entourage of Trest enters the battlefield, you become the monarch.\nEntourage of Trest can block an additional creature each combat as long as you're the monarch. diff --git a/forge-gui/res/cardsfolder/upcoming/archon_of_coronation.txt b/forge-gui/res/cardsfolder/upcoming/archon_of_coronation.txt index f68662bebe9..6abb6d4b093 100755 --- a/forge-gui/res/cardsfolder/upcoming/archon_of_coronation.txt +++ b/forge-gui/res/cardsfolder/upcoming/archon_of_coronation.txt @@ -5,5 +5,5 @@ PT:5/5 K:Flying T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMonarch | TriggerDescription$ When CARDNAME enters the battlefield, you become the monarch. SVar:TrigMonarch:DB$ BecomeMonarch | Defined$ You -S:Mode$ Continuous | Affected$ You | Condition$ You.isMonarch | AddKeyword$ Damage doesn't cause you to lose life. | Description$ As long as you're the monarch, damage doesn't cause you to lose life. +S:Mode$ Continuous | Affected$ You | Condition$ Monarch | AddKeyword$ Damage doesn't cause you to lose life. | Description$ As long as you're the monarch, damage doesn't cause you to lose life. Oracle:Flying\nWhen Archon of Coronation enters the battlefield, you become the monarch.\nAs long as you're the monarch, damage doesn't cause you to lose life. diff --git a/forge-gui/res/cardsfolder/upcoming/dawnblade_regent.txt b/forge-gui/res/cardsfolder/upcoming/dawnblade_regent.txt index 71f5f107711..f3ea5998b43 100644 --- a/forge-gui/res/cardsfolder/upcoming/dawnblade_regent.txt +++ b/forge-gui/res/cardsfolder/upcoming/dawnblade_regent.txt @@ -4,5 +4,5 @@ Types:Creature Elk PT:8/8 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMonarch | TriggerDescription$ When CARDNAME enters the battlefield, you become the monarch. SVar:TrigMonarch:DB$ BecomeMonarch | Defined$ You -S:Mode$ Continuous | Affected$ Permanent.YouCtrl | AddKeyword$ Hexproof | Condition$ You.isMonarch | Description$ As long as you're the monarch, permanents you control have hexproof. +S:Mode$ Continuous | Affected$ Permanent.YouCtrl | AddKeyword$ Hexproof | Condition$ Monarch | Description$ As long as you're the monarch, permanents you control have hexproof. Oracle:When Dawnglade Regent enters the battlefield, you become the monarch.\nAs long as you're the monarch, permanents you control have hexproof. From e9e6dc934d8d6a79b9d2a8ec9f9f7f5359d5880b Mon Sep 17 00:00:00 2001 From: John Date: Fri, 4 Dec 2020 22:10:33 +0000 Subject: [PATCH 05/97] Update Secret Lair Ultimate Edition.txt --- forge-gui/res/editions/Secret Lair Ultimate Edition.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/forge-gui/res/editions/Secret Lair Ultimate Edition.txt b/forge-gui/res/editions/Secret Lair Ultimate Edition.txt index 33fc84e11c6..9abff16b57b 100644 --- a/forge-gui/res/editions/Secret Lair Ultimate Edition.txt +++ b/forge-gui/res/editions/Secret Lair Ultimate Edition.txt @@ -10,3 +10,9 @@ Type=Reprint 3 R Verdant Catacombs 4 R Arid Mesa 5 R Misty Rainforest +13 R Branchloft Pathway +14 R Brightclimb Pathway +15 R Clearwater Pathway +16 R Cragcrown Pathway +19 R Needleverge Pathway +20 R Riverglide Pathway From 74b3e2697ec8838e63118bb7d87644b7f1aa5d91 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Sat, 5 Dec 2020 13:48:04 +0800 Subject: [PATCH 06/97] update borderlessCardList.txt --- forge-gui/res/lists/borderlessCardList.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/forge-gui/res/lists/borderlessCardList.txt b/forge-gui/res/lists/borderlessCardList.txt index 2b05ed874be..f3b654c592a 100644 --- a/forge-gui/res/lists/borderlessCardList.txt +++ b/forge-gui/res/lists/borderlessCardList.txt @@ -104,6 +104,18 @@ SLD/Oona, Queen of the Fae.fullborder SLD/Saskia the Unyielding.fullborder SLD/The Mimeoplasm.fullborder SLD/Voidslime.fullborder +SLU/Brightclimb Pathway.fullborder +SLU/Clearwater Pathway.fullborder +SLU/Cragcrown Pathway.fullborder +SLU/Grimclimb Pathway.fullborder +SLU/Lavaglide Pathway.fullborder +SLU/Murkwater Pathway.fullborder +SLU/Needleverge Pathway.fullborder +SLU/Pillarverge Pathway.fullborder +SLU/Riverglide Pathway.fullborder +SLU/Timbercrown Pathway.fullborder +SLU/Boulderloft Pathway.fullborder +SLU/Branchloft Pathway.fullborder THB/Ashiok, Nightmare Muse2.fullborder THB/Calix, Destiny's Hand2.fullborder THB/Elspeth, Sun's Nemesis2.fullborder From 8b93e382740ef79008f356ea5da1bc41979c2221 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Sat, 5 Dec 2020 13:49:14 +0800 Subject: [PATCH 07/97] [Mobile] Loading Overlay for Generated Random Quest --- .../src/forge/screens/home/HomeScreen.java | 9 +++++++ .../forge/screens/quest/QuestDuelsScreen.java | 25 ++++++++++++++++--- .../src/forge/screens/quest/QuestMenu.java | 1 + 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/forge-gui-mobile/src/forge/screens/home/HomeScreen.java b/forge-gui-mobile/src/forge/screens/home/HomeScreen.java index dfee6c70139..2c03efda874 100644 --- a/forge-gui-mobile/src/forge/screens/home/HomeScreen.java +++ b/forge-gui-mobile/src/forge/screens/home/HomeScreen.java @@ -38,6 +38,7 @@ public class HomeScreen extends FScreen { private int activeButtonIndex, baseButtonCount; private FDeckChooser deckManager; private boolean QuestCommander = false; + private String QuestWorld = ""; private HomeScreen() { super((Header)null); @@ -109,10 +110,18 @@ public class HomeScreen extends FScreen { QuestCommander = isCommander; } + public void updateQuestWorld(String questWorld){ + QuestWorld = questWorld; + } + public boolean getQuestCommanderMode() { return QuestCommander; } + public String getQuestWorld() { + return QuestWorld; + } + public void addButtonForMode(String caption, final FEventHandler command) { //ensure we don't add the same mode button more than once for (int i = baseButtonCount; i < buttons.size(); i++) { diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestDuelsScreen.java b/forge-gui-mobile/src/forge/screens/quest/QuestDuelsScreen.java index 98a138b6365..b9edf03ead6 100644 --- a/forge-gui-mobile/src/forge/screens/quest/QuestDuelsScreen.java +++ b/forge-gui-mobile/src/forge/screens/quest/QuestDuelsScreen.java @@ -2,10 +2,13 @@ package forge.screens.quest; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Align; +import forge.FThreads; import forge.assets.FSkinFont; import forge.interfaces.IButton; import forge.model.FModel; import forge.quest.QuestEventDuel; +import forge.screens.LoadingOverlay; +import forge.screens.home.HomeScreen; import forge.toolbox.FEvent; import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FLabel; @@ -67,18 +70,32 @@ public class QuestDuelsScreen extends QuestLaunchScreen { @Override public void onUpdate() { + //add loading overlay for generated decks... + if (HomeScreen.instance.getQuestWorld().contains("Random")) { + FThreads.invokeInEdtLater(new Runnable() { + @Override + public void run() { + LoadingOverlay.show("Loading Random Quest", new Runnable() { + @Override + public void run() { + generateDuels(); + } + }); + } + }); + } else { + generateDuels(); + } + } + private void generateDuels() { pnlDuels.clear(); - List duels = FModel.getQuest().getDuelsManager().generateDuels(); - if (duels != null) { for (QuestEventDuel duel : duels) { pnlDuels.add(new QuestEventPanel(duel, pnlDuels)); } } - pnlDuels.revalidate(); - } } diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java b/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java index 43bb8e9b21d..a70b4f9a2d1 100644 --- a/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java +++ b/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java @@ -222,6 +222,7 @@ public class QuestMenu extends FPopupMenu implements IVQuestStats { LoadGameScreen.QuestMode.setAsBackScreen(true); } } + HomeScreen.instance.updateQuestWorld(FModel.getQuest().getWorld() == null ? "" : FModel.getQuest().getWorld().toString()); } }); return; From 1bc9fb08d67ba0f193a30b218f85bc421897492c Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Sat, 5 Dec 2020 14:16:22 +0800 Subject: [PATCH 08/97] [Mobile] Update Quest buttons --- .../forge/screens/planarconquest/ConquestMenu.java | 13 +++++++++++++ .../src/forge/screens/quest/QuestMenu.java | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java index 80ee1a8ff28..d585bdad2c4 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java @@ -10,6 +10,7 @@ import forge.menu.FPopupMenu; import forge.model.FModel; import forge.screens.FScreen; import forge.screens.LoadingOverlay; +import forge.screens.home.HomeScreen; import forge.screens.home.LoadGameMenu.LoadGameScreen; import forge.toolbox.FEvent; import forge.toolbox.FEvent.FEventHandler; @@ -81,6 +82,18 @@ public class ConquestMenu extends FPopupMenu { Forge.openScreen(screen0, Forge.getCurrentScreen() != multiverseScreen); } + static { + //the first time planarconquest mode is launched, add button for it if in Landscape mode + if (Forge.isLandscapeMode()) { + HomeScreen.instance.addButtonForMode("-"+Localizer.getInstance().getMessage("lblPlanarConquest"), new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + launchPlanarConquest(LaunchReason.StartPlanarConquest); + } + }); + } + } + public static ConquestMenu getMenu() { return conquestMenu; } diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java b/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java index a70b4f9a2d1..4d183aa111f 100644 --- a/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java +++ b/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java @@ -160,7 +160,7 @@ public class QuestMenu extends FPopupMenu implements IVQuestStats { static { //the first time quest mode is launched, add button for it if in Landscape mode if (Forge.isLandscapeMode()) { - HomeScreen.instance.addButtonForMode(Localizer.getInstance().getMessage("lblQuestMode"), new FEventHandler() { + HomeScreen.instance.addButtonForMode("-"+Localizer.getInstance().getMessage("lblQuestMode"), new FEventHandler() { @Override public void handleEvent(FEvent e) { launchQuestMode(LaunchReason.StartQuestMode, HomeScreen.instance.getQuestCommanderMode()); From db77e2861ca32d3e4c016087c4370ec0bb179c68 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Sat, 5 Dec 2020 10:08:41 +0100 Subject: [PATCH 09/97] CardDb: dont keep allCards list just use values collection --- forge-core/src/main/java/forge/card/CardDb.java | 7 ++----- forge-core/src/main/java/forge/card/ICardDatabase.java | 6 +++--- forge-gui/src/main/java/forge/quest/QuestWorld.java | 3 ++- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/forge-core/src/main/java/forge/card/CardDb.java b/forge-core/src/main/java/forge/card/CardDb.java index f672c12e09a..6703f58075b 100644 --- a/forge-core/src/main/java/forge/card/CardDb.java +++ b/forge-core/src/main/java/forge/card/CardDb.java @@ -50,8 +50,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool { private final Map alternateName = Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER); private final Map artIds = new HashMap<>(); - private final List allCards = new ArrayList<>(); - private final List roAllCards = Collections.unmodifiableList(allCards); + private final Collection roAllCards = Collections.unmodifiableCollection(allCardsByName.values()); private final CardEdition.Collection editions; public enum SetPreference { @@ -247,10 +246,8 @@ public final class CardDb implements ICardDatabase, IDeckGenPool { private void reIndex() { uniqueCardsByName.clear(); - allCards.clear(); for (Entry> kv : allCardsByName.asMap().entrySet()) { uniqueCardsByName.put(kv.getKey(), getFirstWithImage(kv.getValue())); - allCards.addAll(kv.getValue()); } } @@ -537,7 +534,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool { } @Override - public List getAllCards() { + public Collection getAllCards() { return roAllCards; } diff --git a/forge-core/src/main/java/forge/card/ICardDatabase.java b/forge-core/src/main/java/forge/card/ICardDatabase.java index a6256207fc7..a83faea5b4d 100644 --- a/forge-core/src/main/java/forge/card/ICardDatabase.java +++ b/forge-core/src/main/java/forge/card/ICardDatabase.java @@ -24,9 +24,9 @@ public interface ICardDatabase extends Iterable { int getArtCount(String cardName, String edition); Collection getUniqueCards(); - List getAllCards(); - List getAllCards(String cardName); - List getAllCards(Predicate predicate); + Collection getAllCards(); + Collection getAllCards(String cardName); + Collection getAllCards(Predicate predicate); List getAllCardsFromEdition(CardEdition edition); diff --git a/forge-gui/src/main/java/forge/quest/QuestWorld.java b/forge-gui/src/main/java/forge/quest/QuestWorld.java index 651e285624f..f69cbe5d7df 100644 --- a/forge-gui/src/main/java/forge/quest/QuestWorld.java +++ b/forge-gui/src/main/java/forge/quest/QuestWorld.java @@ -27,6 +27,7 @@ import forge.util.storage.StorageReaderFile; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -102,7 +103,7 @@ public class QuestWorld implements Comparable{ return format; } - public List getAllCards() { + public Collection getAllCards() { GameFormat format0 = format; if (format0 == null) { format0 = FModel.getQuest().getMainFormat(); From f0f6f70b28be0baeadda26aee4fe0b2fe05fe8d8 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Sat, 5 Dec 2020 11:34:00 +0100 Subject: [PATCH 10/97] StaticAbilityCastWithFlash: refactor that it can be checked before targets --- .../java/forge/game/spellability/Spell.java | 6 +- .../forge/game/spellability/SpellAbility.java | 14 +--- .../spellability/SpellAbilityRestriction.java | 21 +++-- .../game/staticability/StaticAbility.java | 18 ---- .../StaticAbilityCastWithFlash.java | 84 ++++++++++++++----- 5 files changed, 87 insertions(+), 56 deletions(-) diff --git a/forge-game/src/main/java/forge/game/spellability/Spell.java b/forge-game/src/main/java/forge/game/spellability/Spell.java index 4bbe33935f2..baca8b77c1e 100644 --- a/forge-game/src/main/java/forge/game/spellability/Spell.java +++ b/forge-game/src/main/java/forge/game/spellability/Spell.java @@ -17,6 +17,8 @@ */ package forge.game.spellability; +import org.apache.commons.lang3.ObjectUtils; + import forge.card.CardStateName; import forge.card.mana.ManaCost; import forge.game.Game; @@ -100,7 +102,9 @@ public abstract class Spell extends SpellAbility implements java.io.Serializable card.setController(activator, 0); } - if (!this.getRestrictions().canPlay(getHostCard(), this)) { + card = ObjectUtils.firstNonNull(getAlternateHost(card), card); + + if (!this.getRestrictions().canPlay(card, this)) { return false; } diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java index 887fd94252e..2345598569d 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -47,6 +47,7 @@ import forge.game.player.Player; import forge.game.player.PlayerCollection; import forge.game.replacement.ReplacementEffect; import forge.game.staticability.StaticAbility; +import forge.game.staticability.StaticAbilityCastWithFlash; import forge.game.trigger.Trigger; import forge.game.trigger.TriggerType; import forge.game.trigger.WrappedAbility; @@ -2059,17 +2060,8 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit return true; } } - final Game game = activator.getGame(); - final CardCollection allp = new CardCollection(game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)); - allp.add(host); - for (final Card ca : allp) { - for (final StaticAbility stAb : ca.getStaticAbilities()) { - if (stAb.applyAbility("CastWithFlash", host, this, activator)) { - return true; - } - } - } - return false; + + return StaticAbilityCastWithFlash.anyWithFlash(this, host, activator); } } diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbilityRestriction.java b/forge-game/src/main/java/forge/game/spellability/SpellAbilityRestriction.java index 6c38eccddf2..069b3fed888 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbilityRestriction.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbilityRestriction.java @@ -6,12 +6,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -24,6 +24,7 @@ import forge.game.card.*; import forge.game.cost.IndividualCostPaymentInstance; import forge.game.phase.PhaseType; import forge.game.player.Player; +import forge.game.staticability.StaticAbilityCastWithFlash; import forge.game.zone.Zone; import forge.game.zone.ZoneType; import forge.util.Expressions; @@ -35,7 +36,7 @@ import java.util.Map; *

* SpellAbilityRestriction class. *

- * + * * @author Forge * @version $Id$ */ @@ -61,7 +62,7 @@ public class SpellAbilityRestriction extends SpellAbilityVariables { *

* setRestrictions. *

- * + * * @param params * a {@link java.util.HashMap} object. * @since 1.0.15 @@ -321,7 +322,7 @@ public class SpellAbilityRestriction extends SpellAbilityVariables { String validPlayer = this.getActivator(); return activator.isValid(validPlayer, c.getController(), c, sa); } - + public final boolean checkOtherRestrictions(final Card c, final SpellAbility sa, final Player activator) { final Game game = activator.getGame(); @@ -484,7 +485,7 @@ public class SpellAbilityRestriction extends SpellAbilityVariables { *

* canPlay. *

- * + * * @param c * a {@link forge.game.card.Card} object. * @param sa @@ -503,6 +504,12 @@ public class SpellAbilityRestriction extends SpellAbilityVariables { System.out.println(c.getName() + " Did not have activator set in SpellAbilityRestriction.canPlay()"); } + if (!StaticAbilityCastWithFlash.anyWithFlashNeedsTargeting(sa, c, activator)) { + if (!sa.canCastTiming(c, activator)) { + return false; + } + } + if (!sa.hasSVar("IsCastFromPlayEffect")) { if (!checkTimingRestrictions(c, sa)) { return false; @@ -516,7 +523,7 @@ public class SpellAbilityRestriction extends SpellAbilityVariables { if (!checkZoneRestrictions(c, sa)) { return false; } - + if (!checkOtherRestrictions(c, sa, activator)) { return false; } diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java index 8f2d8987037..8d2f5392fec 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java @@ -403,24 +403,6 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone return false; } - public final boolean applyAbility(final String mode, final Card card, final SpellAbility spellAbility, final Player player) { - - // don't apply the ability if it hasn't got the right mode - if (!getParam("Mode").equals(mode)) { - return false; - } - - if (this.isSuppressed() || !this.checkConditions()) { - return false; - } - - if (mode.equals("CastWithFlash")) { - return StaticAbilityCastWithFlash.applyWithFlashAbility(this, spellAbility, card, player); - } - - return false; - } - public final boolean applyAbility(String mode, Card card, CounterType type) { // don't apply the ability if it hasn't got the right mode diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityCastWithFlash.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCastWithFlash.java index aa52bb57c9d..08e4a883ecc 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityCastWithFlash.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCastWithFlash.java @@ -1,15 +1,57 @@ package forge.game.staticability; -import java.util.List; +import com.google.common.collect.Iterables; -import forge.game.GameObject; +import forge.game.Game; +import forge.game.GameObjectPredicates; import forge.game.card.Card; +import forge.game.card.CardCollection; import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; public class StaticAbilityCastWithFlash { - public static boolean applyWithFlashAbility(final StaticAbility stAb, final SpellAbility sa, final Card card, final Player activator) { + + static String MODE = "CastWithFlash"; + + public static boolean anyWithFlashNeedsTargeting(final SpellAbility sa, final Card card, final Player activator) { + final Game game = activator.getGame(); + final CardCollection allp = new CardCollection(game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)); + allp.add(card); + for (final Card ca : allp) { + for (final StaticAbility stAb : ca.getStaticAbilities()) { + if (!stAb.getParam("Mode").equals(MODE) || stAb.isSuppressed() || !stAb.checkConditions()) { + continue; + } + if (applyWithFlashNeedsTargeting(stAb, sa, card, activator)) { + return true; + } + } + } + return false; + } + + public static boolean anyWithFlash(final SpellAbility sa, final Card card, final Player activator) { + final Game game = activator.getGame(); + final CardCollection allp = new CardCollection(game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)); + allp.add(card); + for (final Card ca : allp) { + for (final StaticAbility stAb : ca.getStaticAbilities()) { + if (!stAb.getParam("Mode").equals(MODE) || stAb.isSuppressed() || !stAb.checkConditions()) { + continue; + } + if (applyWithFlashAbility(stAb, sa, card, activator)) { + return true; + } + } + } + return false; + } + + + + + public static boolean commonParts(final StaticAbility stAb, final SpellAbility sa, final Card card, final Player activator) { final Card hostCard = stAb.getHostCard(); if (stAb.hasParam("ValidCard") @@ -21,32 +63,36 @@ public class StaticAbilityCastWithFlash { && !sa.isValid(stAb.getParam("ValidSA").split(","), hostCard.getController(), hostCard, null)) { return false; } - + if (stAb.hasParam("Caster") && (activator != null) && !activator.isValid(stAb.getParam("Caster"), hostCard.getController(), hostCard, null)) { return false; } + return true; + } + + public static boolean applyWithFlashNeedsTargeting(final StaticAbility stAb, final SpellAbility sa, final Card card, final Player activator) { + if (!commonParts(stAb, sa, card, activator)) { + return false; + } + + return stAb.hasParam("Targeting"); + } + + public static boolean applyWithFlashAbility(final StaticAbility stAb, final SpellAbility sa, final Card card, final Player activator) { + final Card hostCard = stAb.getHostCard(); + + if (!commonParts(stAb, sa, card, activator)) { + return false; + } if (stAb.hasParam("Targeting")) { if (!sa.usesTargeting()) { return false; } - boolean found = false; - String[] valids = stAb.getParam("Targeting").split(","); - for (GameObject ga : sa.getTargets()) { - if (ga.isValid(valids, hostCard.getController(), hostCard, null)) { - found = true; - break; - } - } - if (!found) { - return false; - } - } - if (stAb.hasParam("Origin")) { - List src = ZoneType.listValueOf(stAb.getParam("Origin")); - if (!src.contains(hostCard.getGame().getZoneOf(card).getZoneType())) { + String[] valids = stAb.getParam("Targeting").split(","); + if (!Iterables.any(sa.getTargets(), GameObjectPredicates.restriction(valids, hostCard.getController(), hostCard, null))) { return false; } } From 72b756aa8e0957281ed5114f84b5185f70de8400 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Sat, 5 Dec 2020 20:35:59 +0800 Subject: [PATCH 11/97] [Mobile] Add dialog to restart Forge --- forge-gui-mobile/src/forge/assets/AssetsDownloader.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/forge-gui-mobile/src/forge/assets/AssetsDownloader.java b/forge-gui-mobile/src/forge/assets/AssetsDownloader.java index fc4971ea829..5d60a50690f 100644 --- a/forge-gui-mobile/src/forge/assets/AssetsDownloader.java +++ b/forge-gui-mobile/src/forge/assets/AssetsDownloader.java @@ -155,5 +155,11 @@ public class AssetsDownloader { //save version string to file once assets finish downloading //so they don't need to be re-downloaded until you upgrade again FileUtil.writeFile(versionFile, Forge.CURRENT_VERSION); + + //add restart after assets update + switch (SOptionPane.showOptionDialog("Resource update finished. Please restart Forge.", "", null, ImmutableList.of("Ok"))) { + default: + Forge.restart(true); + } } } From c0a8abcb3f8294ff0f153ec3366c1da16c3e0e17 Mon Sep 17 00:00:00 2001 From: John Date: Sat, 5 Dec 2020 12:40:53 +0000 Subject: [PATCH 12/97] Update Secret Lair Drop Series.txt --- forge-gui/res/editions/Secret Lair Drop Series.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/forge-gui/res/editions/Secret Lair Drop Series.txt b/forge-gui/res/editions/Secret Lair Drop Series.txt index 868f0f9539f..17d5619a230 100644 --- a/forge-gui/res/editions/Secret Lair Drop Series.txt +++ b/forge-gui/res/editions/Secret Lair Drop Series.txt @@ -184,6 +184,7 @@ Type=Other 535 U Samut, Tyrant Smasher 536 U Vraska, Swarm's Eminence 537 M Tibalt, the Fiend-Blooded +538 R Evolving Wilds 581 M Lucille [tokens] From d67b1595bcce2406e651326a3f77e1c49057be28 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Sat, 5 Dec 2020 16:36:55 +0100 Subject: [PATCH 13/97] move wrong_turn.txt --- .../forge/forge-gui/res/cardsfolder => }/upcoming/wrong_turn.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename forge-gui/res/cardsfolder/{w/forge/forge-gui/res/cardsfolder => }/upcoming/wrong_turn.txt (100%) diff --git a/forge-gui/res/cardsfolder/w/forge/forge-gui/res/cardsfolder/upcoming/wrong_turn.txt b/forge-gui/res/cardsfolder/upcoming/wrong_turn.txt similarity index 100% rename from forge-gui/res/cardsfolder/w/forge/forge-gui/res/cardsfolder/upcoming/wrong_turn.txt rename to forge-gui/res/cardsfolder/upcoming/wrong_turn.txt From 1da617424f2ee1a6634e08ef1ddf10379bc9afce Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Sat, 5 Dec 2020 17:25:08 +0100 Subject: [PATCH 14/97] ChangeZoneAi: fix AI if no Origin Zone, use zones from TargetRestrictions --- .../java/forge/ai/ability/ChangeZoneAi.java | 31 +++++-------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java index 468ed9ccf72..12f5966d29e 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java @@ -1353,29 +1353,13 @@ public class ChangeZoneAi extends SpellAbilityAi { } final Card source = sa.getHostCard(); - final ZoneType origin = ZoneType.listValueOf(sa.getParam("Origin")).get(0); final ZoneType destination = ZoneType.smartValueOf(sa.getParam("Destination")); final TargetRestrictions tgt = sa.getTargetRestrictions(); - CardCollection list = CardLists.getValidCards(ai.getGame().getCardsIn(origin), tgt.getValidTgts(), ai, source, sa); + CardCollection list = CardLists.getValidCards(ai.getGame().getCardsIn(tgt.getZone()), tgt.getValidTgts(), ai, source, sa); + list = CardLists.getTargetableCards(list, sa); - // Narrow down the list: - if (origin.equals(ZoneType.Battlefield)) { - // filter out untargetables - list = CardLists.getTargetableCards(list, sa); - - // if Destination is hand, either bounce opponents dangerous stuff - // or save my about to die stuff - - // if Destination is exile, filter out my cards - } - else if (origin.equals(ZoneType.Graveyard)) { - // Retrieve from Graveyard to: - } - - for (final Card c : sa.getTargets().getTargetCards()) { - list.remove(c); - } + list.removeAll(sa.getTargets().getTargetCards()); if (list.isEmpty()) { return false; @@ -1387,12 +1371,13 @@ public class ChangeZoneAi extends SpellAbilityAi { Card choice = null; if (!list.isEmpty()) { - if (ComputerUtilCard.getMostExpensivePermanentAI(list, sa, false).isCreature() - && (destination.equals(ZoneType.Battlefield) || origin.equals(ZoneType.Battlefield))) { + Card mostExpensivePermanent = ComputerUtilCard.getMostExpensivePermanentAI(list, sa, false); + if (mostExpensivePermanent.isCreature() + && (destination.equals(ZoneType.Battlefield) || tgt.getZone().contains(ZoneType.Battlefield))) { // if a creature is most expensive take the best choice = ComputerUtilCard.getBestCreatureToBounceAI(list); - } else if (destination.equals(ZoneType.Battlefield) || origin.equals(ZoneType.Battlefield)) { - choice = ComputerUtilCard.getMostExpensivePermanentAI(list, sa, false); + } else if (destination.equals(ZoneType.Battlefield) || tgt.getZone().contains(ZoneType.Battlefield)) { + choice = mostExpensivePermanent; } else if (destination.equals(ZoneType.Hand) || destination.equals(ZoneType.Library)) { List nonLands = CardLists.getNotType(list, "Land"); // Prefer to pull a creature, generally more useful for AI. From 3ba79ea606d2759e7465a503bf0783f8d8b3e609 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Sun, 6 Dec 2020 16:39:51 +0800 Subject: [PATCH 15/97] [Mobile] Add Landwalk and Commander Icons --- .../main/java/forge/game/card/CardView.java | 4 ++++ .../forge/trackable/TrackableProperty.java | 1 + .../src/forge/assets/FSkinImage.java | 3 +++ .../src/forge/card/CardFaceSymbols.java | 2 ++ .../src/forge/card/CardRenderer.java | 10 ++++++++++ .../res/skins/default/sprite_ability.png | Bin 231353 -> 243945 bytes .../src/main/java/forge/assets/FSkinProp.java | 5 ++++- .../forge/quest/QuestWinLoseController.java | 9 +++++++-- 8 files changed, 31 insertions(+), 3 deletions(-) diff --git a/forge-game/src/main/java/forge/game/card/CardView.java b/forge-game/src/main/java/forge/game/card/CardView.java index 16c7ab0210d..f2d162494e8 100644 --- a/forge-game/src/main/java/forge/game/card/CardView.java +++ b/forge-game/src/main/java/forge/game/card/CardView.java @@ -1145,6 +1145,9 @@ public class CardView extends GameEntityView { public boolean hasStorm() { return get(TrackableProperty.HasStorm); } + public boolean hasLandwalk() { + return get(TrackableProperty.HasLandwalk); + } public String getAbilityText() { return get(TrackableProperty.AbilityText); @@ -1175,6 +1178,7 @@ public class CardView extends GameEntityView { set(TrackableProperty.HasHaste, c.hasKeyword(Keyword.HASTE, state)); set(TrackableProperty.HasInfect, c.hasKeyword(Keyword.INFECT, state)); set(TrackableProperty.HasStorm, c.hasKeyword(Keyword.STORM, state)); + set(TrackableProperty.HasLandwalk, c.hasKeyword(Keyword.LANDWALK, state)); updateAbilityText(c, state); //set protectionKey for Icons set(TrackableProperty.ProtectionKey, c.getProtectionKey()); diff --git a/forge-game/src/main/java/forge/trackable/TrackableProperty.java b/forge-game/src/main/java/forge/trackable/TrackableProperty.java index c1c1c09f676..a8ce01b8c2c 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableProperty.java +++ b/forge-game/src/main/java/forge/trackable/TrackableProperty.java @@ -114,6 +114,7 @@ public enum TrackableProperty { HasShroud(TrackableTypes.BooleanType), HasTrample(TrackableTypes.BooleanType), HasVigilance(TrackableTypes.BooleanType), + HasLandwalk(TrackableTypes.BooleanType), //protectionkey ProtectionKey(TrackableTypes.StringType), //hexproofkey diff --git a/forge-gui-mobile/src/forge/assets/FSkinImage.java b/forge-gui-mobile/src/forge/assets/FSkinImage.java index 5926e5e05e8..927a97f766a 100644 --- a/forge-gui-mobile/src/forge/assets/FSkinImage.java +++ b/forge-gui-mobile/src/forge/assets/FSkinImage.java @@ -351,6 +351,8 @@ public enum FSkinImage implements FImage { FOIL_19 (FSkinProp.FOIL_19, SourceFile.OLD_FOILS), FOIL_20 (FSkinProp.FOIL_20, SourceFile.OLD_FOILS), + //COMMANDER + IMG_ABILITY_COMMANDER (FSkinProp.IMG_ABILITY_COMMANDER, SourceFile.ABILITIES), //ABILITY ICONS IMG_ABILITY_DEATHTOUCH (FSkinProp.IMG_ABILITY_DEATHTOUCH, SourceFile.ABILITIES), IMG_ABILITY_DEFENDER (FSkinProp.IMG_ABILITY_DEFENDER, SourceFile.ABILITIES), @@ -364,6 +366,7 @@ public enum FSkinImage implements FImage { IMG_ABILITY_HORSEMANSHIP (FSkinProp.IMG_ABILITY_HORSEMANSHIP, SourceFile.ABILITIES), IMG_ABILITY_INDESTRUCTIBLE (FSkinProp.IMG_ABILITY_INDESTRUCTIBLE, SourceFile.ABILITIES), IMG_ABILITY_INTIMIDATE (FSkinProp.IMG_ABILITY_INTIMIDATE, SourceFile.ABILITIES), + IMG_ABILITY_LANDWALK (FSkinProp.IMG_ABILITY_LANDWALK, SourceFile.ABILITIES), IMG_ABILITY_LIFELINK (FSkinProp.IMG_ABILITY_LIFELINK, SourceFile.ABILITIES), IMG_ABILITY_MENACE (FSkinProp.IMG_ABILITY_MENACE, SourceFile.ABILITIES), IMG_ABILITY_REACH (FSkinProp.IMG_ABILITY_REACH, SourceFile.ABILITIES), diff --git a/forge-gui-mobile/src/forge/card/CardFaceSymbols.java b/forge-gui-mobile/src/forge/card/CardFaceSymbols.java index 96f355dd730..a26bc910f45 100644 --- a/forge-gui-mobile/src/forge/card/CardFaceSymbols.java +++ b/forge-gui-mobile/src/forge/card/CardFaceSymbols.java @@ -102,6 +102,7 @@ public class CardFaceSymbols { MANA_IMAGES.put("foil19", FSkinImage.FOIL_19); MANA_IMAGES.put("foil20", FSkinImage.FOIL_20); + MANA_IMAGES.put("commander", FSkinImage.IMG_ABILITY_COMMANDER); MANA_IMAGES.put("deathtouch", FSkinImage.IMG_ABILITY_DEATHTOUCH); MANA_IMAGES.put("defender", FSkinImage.IMG_ABILITY_DEFENDER); @@ -115,6 +116,7 @@ public class CardFaceSymbols { MANA_IMAGES.put("horsemanship", FSkinImage.IMG_ABILITY_HORSEMANSHIP); MANA_IMAGES.put("indestructible", FSkinImage.IMG_ABILITY_INDESTRUCTIBLE); MANA_IMAGES.put("intimidate", FSkinImage.IMG_ABILITY_INTIMIDATE); + MANA_IMAGES.put("landwalk", FSkinImage.IMG_ABILITY_LANDWALK); MANA_IMAGES.put("lifelink", FSkinImage.IMG_ABILITY_LIFELINK); MANA_IMAGES.put("menace", FSkinImage.IMG_ABILITY_MENACE); MANA_IMAGES.put("reach", FSkinImage.IMG_ABILITY_REACH); diff --git a/forge-gui-mobile/src/forge/card/CardRenderer.java b/forge-gui-mobile/src/forge/card/CardRenderer.java index 21dca687712..504e5da3bc3 100644 --- a/forge-gui-mobile/src/forge/card/CardRenderer.java +++ b/forge-gui-mobile/src/forge/card/CardRenderer.java @@ -654,6 +654,11 @@ public class CardRenderer { abiY += abiSpace; abiCount += 1; } + if (card.isCommander()) { + CardFaceSymbols.drawSymbol("commander", g, abiX, abiY, abiScale, abiScale); + abiY += abiSpace; + abiCount += 1; + } if (card.getCurrentState().hasFlying()) { CardFaceSymbols.drawSymbol("flying", g, abiX, abiY, abiScale, abiScale); abiY += abiSpace; @@ -716,6 +721,11 @@ public class CardRenderer { abiY += abiSpace; abiCount += 1; } + if (card.getCurrentState().hasLandwalk()) { + CardFaceSymbols.drawSymbol("landwalk", g, abiX, abiY, abiScale, abiScale); + abiY += abiSpace; + abiCount += 1; + } if (card.getCurrentState().hasHexproof()) { if (abiCount > 5 ) { abiY = cy + (abiSpace * (abiCount - 6)); abiX = cx + ((cw*2)/1.92f); } if (!card.getCurrentState().getHexproofKey().isEmpty()){ diff --git a/forge-gui/res/skins/default/sprite_ability.png b/forge-gui/res/skins/default/sprite_ability.png index 7b25e07fcbeb8038d5e3089a1857d76164c6f3ce..c33b526a74f0d566321ca09d178064d673b86fbf 100644 GIT binary patch delta 47728 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 NR#Hi#OzgAY{{c!`bq@dl delta 35052 zcma%iRZtyGv~EanmyNqiaCZq#g1fuB1|KB2LvVL@_uvrR-92nP1c$r-I_JLJr~5iJ zHB(({b+6C*^cuB24mF4>rGdGhd8z&bT4<9odHwPylA0rt%D;qBhD=!Nh z2NN4NKPPMbpH(PSR!$~1PBnIReokI~cCMt^kEH+aqqmP#!MFMCdN#B z+?-rY#;kl6OuQzX7N*8L>?S5`yh)j#q8nSGccA|N-e!U!g883+D!_;&eTBtIVusU( zXYoBk{O~EDFgOk_EDjE;H4g4$+apl% zh3}m#b9|V)|ZY0ZTlBtVxb)stUqr6AMit;?<4fStX zOL30=&ygojRp6iDgQk0=bn2>Q_awVj?c!;itD^-ZBF0qHZ^zEufSuO#&Ea@DySZFu zbFPd}|9i3{4Ld5#t zM(odC`@KIqwzUHtE#FLeEJh7L(LkE$3{he|Ne6Ajo`2ytE3)6Lhi7+D@w`^eVzDqwD$nB zAh{L&XXikWlV7 zSEQvi{jgh?+q?A)f3{S!AL?~QOO{kXQ+I_Sr4W`!>vnzDQU+^KhOT|YX}gv(kx2k1^ zX^*>i0cfzp9K3$BI0-M1F!rbS2*U~!N>)sDFdd?8WwqE)vX~Hza@>A6Z_E4&k`yej z=Fon|>^7HHSGTgNF#8>ypCw#=hi2MoiVkCu%@eA>&ahfvyvIxRzf9eE znRuH8LcsERRB&|Wo|>EuA&05wl%^36;U90qJR!j zI+m#K&_z-lFda@+QOoFi6B4>a*u-+X^9Mmgl?ufKfidW8&}U?wHJtN&g@D)F*NIG? zxN6;&+v`M@2VlD^D}MmC)kiRZ%~bm4w$p#u5x5nQi~P##H+KsCQB1?HJ{I@=m5oap zprVqEJ+aD7ySLHRK9pKlOiGJ;&2pADwL`KucOep^}rlucVjg*DVhBzi}2=DjlR!X z+hgpRl0Zbx>g>-XP<4!+`=sP1zm!gBW>gP1RO<7fcikxge@kIOX!(5#hv}5ea4cc6 zQzpKvRDx#wnvEYFxNyoRZPhh1X(s1knM2R_jcX#qAL@9zGdxcCscaL&|LN2c&;#z| zCo=u;U8nfsq)EMySxXpcvXs|mVMu7*4*fy#=ARubX{>WT&I!Vp72nfxbpNQD_(<@F z(DO8;HO>3qph7}RM8V#dnw}>c1MgF80zyLVRu3%TZ8C~z>yj4qkInlFGtb+O-I1Xy zgEfBls%v>zc-l8~Xf^d1ZZJAD0Hw@xAnx8bL!#-9f>Ma)(RsU(FfFiAQ!4KGn3o?V z#ne$kd6GvjrFdbgk4gjOK?a8h^9_pT<4p>a@6-1C%?6g@6_{hX&U_r_W8jBC(Y#GI zF7Iye1DFG~_l-YgAS?koux?W7WI?sw;5#uNu7Qlk$H|}^Q8jf&;cd2ZU^_NvACII{ z*D6ZSU0+%`NGn@xs?!d7yK~=nt}$z2d68}RuUIsRKq5GrT}6lwnN+x7@hzi7*>Kq{ zS{iuCw=pIl_{{72B=Z~A{T-HwyCS?DH%1Da_jPs*QJ?3Bkevgmrr~$z%yn}!ueOH@ z1ZQ>h4}DHpTf=g4&xBqez_GVI4G?+3@W_wOYElNT=}f+N{#)<5-||6->)cC9e)%&J zr`)4SGb9Y{Se=}^as4&N=O4_6(3n5VUp2jbjTcjc zD#YeN7H$;#J=8RcLfQTy)I{{PRG&ErE8}BI=*@5{Hr$>CX%tBM0hrY6-|jr})B-$* zczW8?=(@KXE(V>{vwzK*zJGH(_ZTsCaP2C9#*`A6CjUjX!)Ww#dpfZA>*KQD{q?q{ zq4{_U6L`HfPN~dZva4=7tgs^^D1$)d!=y={uHLtu2@ct8&WMGV7X#AHvWn5Z9X5CC zXQlU9PXhNgs)k!VWPrp#RIK-#gmO_m`RGziSUK-Tz%;IC3;aqptBo(c=D!shlx(P7MdeN;o6ar zOm16f9}nWg+c*Ih9j69S<=_Rc@%E=sj&(a7)`+kj9fM%X!6 zXyluJA3jC=m~_wnYZSjI9ecGjujqQPBgWizfN94~2(-7iBa~JU#1Zv%xPNBOMMJQX z`${Qji^JDwk)W*R_Klz$J|lERELl=8=Y-_s)tjGc>I=Ko0^AJT zelYT?R{*y<+gtS8&!0HoyTsv~+Rw9qRZkE5N-OelFPDM8E&Ao;%wV(O*W%@zsi|sd z-nv%U5AvGIi>x?NAsHF41hx{4IHt^64P$1-$(V@GEA5w9DNOpq)VC}VB)0QUn+xh= zyx;_WlQFrD(hr7GOwXS+l(m&5H8ea5jI)%KxBwV+6z8p%d9C{)C{&WNypmlq%_)&! zD09gG3>PK_=3kd+b>F9jr_wo!g9}??pv+&juP!M1jYC$CbAN+xv5pzN=pk z-E1OMN-01$QCX|Lch=6#xoUul)qje{Ow4Au-qaHh#o|&$dtLfQN8kP(J^Mo}prxT6 z!U(`46YwQkTV@Z1V^mXC$2|Xo)L}&(TSO^6@yo?edQdc;^8}dXg9%U5TxZb!w+;S^ z3Un31G}l@9sm_OQE-sCj4%Us@dkd*LCPOzdMEpu2Ll`vFi;~_cpH^`Wo*aD}7qR?V z@l0krE8$_A3>Y*8*w7K5uV7+bj#iINngI{PLTP1?Mzzl5$!sA#^W;(2qp8>1n4(Xf zslSQXVm~LRI=lPP&JQ$qCg-9q%+m28$iTt`-Z$SfU{s(3Gct78IXHL^|B6+;m^luP zbNuX3(c>#BJ=}9?=kvTG)2K|2jz%UzrS-7wdI+N%(_&Jf$!1IFdeO77Rd|6b21IAR z%D+O@yd9yXyBiR%w_cRaYK|{hS0kvatGjVRzTM&1v$0`U#f>0|U^?O36619{LJt3t zlyPO_!efL$Sp_TR$+FQ4uE{^f4$sRTLl`&KImtGoam{`61S9rC(@8&0_5G5h1b-}u z2nik!{|Fy%vzHNX%+~ho>~Uudpj~wz#s^_zQ&Tx~m%w_x`*TX>!>&-u7Pae*2=AWa zk@hZ!>!MF2hPC7smKlGsVLHwdiM~Bnq!j4fC!Lj8>Ahq{+R~EbtqLfPh-O671WXC$ zr-=u5`pm0a3}3boxoh~M$^I6po<+bEnp;vf2#wb53RMdIG*6dA!fo6G=2;%L?j0=V zn#im4>cix1(eCD~o^kT);zEZJX>y#EOIxKlTx|Ol>MA@rbIbevqG6YC_lMTUJrg8Lho|W4b+>6jL|)w}HR$7R9%q z<`Z*875XP_lPiX8KXk_lSn)c|j*Bfu@P-M@OTDRJvRkQ3S1t@q%FbLmY6&9Cqucd3 zCKdQX2cjTCETqk=3x#DN1zy;2R{O&-DCy`XjvH)g@A#ZEi!8h=Oa8T{mo0hMtb@Mr zU5IlH7oR$l`!y13aSoDtZ7;LVQ*Ywsy9(?qxo`B5IaDSu{2cTGQ2!aBcb6l`FPFoi zS`mB->NB-*>Qh4Fw-^cAKXI;{dqi(8M7tT;PB@1X;jtJ2K(wlmDlOy+$tZwth&(N!QC9kj`bvZ>k`h#p`*sW4z^i z$Cbjo5jHu;pZO{gL??IBF*SYJ6-Art9Ubk_WnH-#G=2z}T;_BmlWaUj-)Q|eqS29Q zs$ziKyO5VZH6r_HoJ#z8;a`spr6McqbdULPl%V(TWtSMkD?YGKx^4yqFiWvdQO|$n zsl9&i+ji5ZOB+xD__#?M~KaUWIe!)@9gGI3e9r+=1=!={)+rN3mQp4WC zvFwW`&I2Im<45UObQO>d0ikxY3w1~^ESt$-ILY0*15ywj#b2_IYxsXvHnif*6k0Sz z)@8J6_ZliK+@qRa{Y6;1uW))FS5=ADu%fwf;pxRVnVczp^?eHS+EHXtRV^o%rBxt3 z+6pLuwZ2(qw~~?NTrKXLQHvS&E~~k@-f)#lxxE5rU-9@G?m3vBKUNS>;N7%5s*xb+ zFKf5jpj8w!?j@;%?s$%J&biUNw8h6{@PBQ;y|7GWL*T0A!c6326$fMD_MFY2y1$x-n)AcwD|*nXRHMbA^Gb&~Ep@RZZ?-}Zn|{j2 zKr#WIW%eRBg5a;Em=1D>&A7tGeYTaIel?~c5;>KR71laUdQ~hK0;!uWc1J6URPcD@ zw@n2UQhLrXlvBLHf1?M{5~dO{iS~!db%5&803FSd(kPtzzlCvSRaJsC%QRYy;rgJ6 zQwHzk$u-3CvWzcDh7PRuD)n_J7M^4~&L> zw+=%i-3{#R8V%fpB5DD-5$llq|D21DC+8%p?bOn^|K>6=ZlboyUTzDwe$Lb@hgss zkk?8TbHm*8KH7q+>V^4bELYdd9sre`>Ci*(0z$f5yjl_2l2A3PsLTve&+)%eH}JK< z;I1Sr6~az!L=O{!krliyb+*Hy1y=DtUBPt=z8-uwGqboVBz;A%T$EEkR3>>ibM>wF z#l2*C`QiT>$@?0u>UAB0yVB}t_?d4nHt&r8bFbFOp`kz=+yxMxYUrD+TqvEGq#Dqw zQQ#Y=AZ3F=f1wAW4krso5C|du4!`3jP*!c9S5_AOWJFw1V>}!EZYZy&3~&<5#v>!B z$&(Xl)Q?Zelzb-)!=^$O8UNed@!nZ{=3QjSOP66YQEHnIhNLczA}wfN%{NG@Apu$( zb-FwoZAW~VpM#fA6J2VuK8PibDvb$qu{9>oHy%LW@`(eHiJ%+ZFI9s#nj&7YXfffT z>6n=>)Tecu))SBr;Ys;_0RARTcVPGu6Q!56I?SRipC7WS%)bu*bXeA#t{dR=HfDn~ zp&CH5JgCogeCo_yp3LRt*W|;LhuDHI_o=JR?FgMrFp>y!fD zu-Lj4SV9ju)8^*9NenjYEO?-DzeNg!+3PO3UhR;}$wksLUig~;vk|bw*;0;_e0=Ar zL44UB7E?mlQRCz7$J1o!oX1u%OQ{Z)Qbo>^c#3zT1AYTp-MTZ zYraX&&C}Bh!e}><$>C5b@0qp3!H5l>%9N5>;$`3*k=_f*9wyjK@!Rr~0&O8{F0|Ak zrA}ooLW;s~q|6f&nr-{+*=6KCquc60%|l7cFly36;QgSJ<>4ir^Ih{eT_BM&=I%}2 zB{t?mT5UyzRM#99Wx3{v)$6IqIpNOB^r;9ZVg2dBel)D)EOl7y{-B#oa_T&i&36nqGJ1`rR!#_8$lX(%gS zHDYLyB*Y{znZO(ENl>5GQ@MXqMO5|*XMU~~fl~&pwm!>5F+ocxe*sZ5He@@k#4YYc zXPRd6dhrfOrNn0(nGA%w;&XMhugA~t_8ALYLyPkRNV1$HSCKcvJ9VXXcGsv&)n&Aw zyFsaxpPlKy0fxQd#tEnFmOaKZM+1~KzW!-aL8o9uMbq( zQpzAIS-Gkd>t>4k%Q)L%;pOs zr7gdZQ1FW{<%_?G+@J?>qS=sxYok%0&qRh$rRsB<;ZAeq+Qlx?@TZ@#kpgoiw^zG> z3nJpp*o0hhS62{(1&EQMli|UeG_F7S3ODkQMc}Axw6EBcs4+z|uEtY;elz-19GtcB zwr@)hwzQHJ$VTnCo;-Wpbi6o3>wTw8)%T}2H;+hyMkD2)AgpCEo4)wudp2AtJ1z5R zC-ic1Z>Us5$*U-5!HqVfVqS@q*B}*GH)qstfR;_X@)Tqvv2XO&sRA*er#D2I<=)?D zO}M5RG|7%0@lMp!RkSl3P|K^U2lbH|)TaJSb8<5@&v*`e{q?(bJG6p9LF8U9G=^vl z!XmJ|Cvd_(EuYMeMt<>JW@bkvGJ;q7RJGBa33t(xS$>>54ZfWcPce^-jPwSwIH*?7 z;a68r?A;K+C`75zO#4SC+Sa4iNpKu?YUFqBFt?N#d^ zLF8MySM;Pz8_}W#@sZ9+9YP+^VtM6kZeMuUf$Gd~O9a@?N(!c-@~%Zg|dXgnBf%8~SCZ#%-;yOyTfnlu&3x zs|eCRWcY5pj{CITEA~pOb6q^GvUu(EJwN3#>keM092#l#|E-N`7&~z~Ai%~+Om5Qt}}lItqSWk*U3MJcrBR~lHvaCNDR(v4jTrwC17F#axn zDhtJ6sO9yHcZWl30F0NJpOTZ=EVl$Lrm|$^WX4sHPgcXaMh~bwetvbj~bf3U$iXoi+^T*qFlWA6dk2{gh z&g1h5f1v2ILGE=Eob+!WDfS!?ZqCnt#pG~kOvYDA!JZWiK-|r6Wt8^SlN31R+X3&Z zHL<#C{Te4M%Cz}Lc`!U2=N4ee;odw_L#!*%=PYk;*V~vs6`=}5yMwKTi+fZMv|iZk^Z1zE3!!-;u_OD|`&zJ&?tSmN#AZN! zUds|+bSDPXRpY6lQpaOZ!JB^ZH#dla4m?l*o-F30?~o2E5$^|4ZwuYsVXW=gb1`*s z&PQ8by&jR>;~pB)#-oWm!(M-)@-m~_l4|g#`-x^+I&-x5>VJei4egT*mkkN5|N zgl1bOC`R=%_UPYpSCruj5=%a`Zh8=kyq+rJ3;P0|S#YIDuzg4!j|>DbW`v#d2o{k)zztqxU-mD*L!}T&_OATl$~xhdoblz z>5so{c9xgdl-SLX4M*dP8yg$z^{0b9_S;V=pw%U-Yb>r}iQ#uynT^hC^cj8b)Y%&w z;9-H_XcCSR=|Lv=kN>iWh*V4RYIG!>h9XG}+-==NH;#OrUij5jXAwB+IFp*1K-{$= z(Y57Fj%z2C_Q}LmTGxE36TNNH42Ica5RGB7!oBNh&!nZgcI13QDkY=QV{#ZCM>@Q5 znz(O*4{MBNv~PXKbYLxbVfoRU&$WREj0d1;HyJhat~OW`<|~y+b2qOtW_dr=X`G>v z+VoByjG0KwCd#@WC*%r6V~=aP?6*1|Y2LpiiUq?`3yyDfKYP98*4BH;e`1#Q?zbYOM-LSJkUAa_9vpMl%I@%j7fXWRa?5kM*NAO+_3qFH9}rM`_kKBMGBTA{Pyn#U z>VYJ8uSarrLyot0tkj7$^?lexULWuIESI#UMm6AMQ?8yrbzS9ZdYvBPKHSg8C1tL+ z*c6nMBUpCC_7d;sm6Vn)X=;$j!|?h(ux>wZ-8=E>C7^rh&O!~Ovz`}AJ{g`dRp^^w zPq@iT%b-u%r^n+6^b()xk6^a7X9Kb;N83lAWVB{yFfuzs?%3?`>_t>5YC8k(e$`B7 zK2D3g^+8OGGX6_Ji-{~*YisL`o`QkEbBM57SsgM$BED7!1s96Bo-q*icqxvSzwJqB zIudi1Trc+tjsgYm!$@u$mbm%=Crm7b41N~7HK#w&rk~6dWjAstV>t$w3pnlkf`a|$ zLdX>$TP}a7Sh_4)>7B(;C z&=UsndzAY}dcIXvdPIjXt~;%$YByR?>T)|8Ppq(Y^S6kSji#WS#~hk96b3-}Gmk5J z-u3C+q@Hgdww~YlVHSriK*P7nM}vEWj@Cb2OQnungzz?{ioh zmn}|@R01uDe@sCE3i{O1%mtZ;Eut=@q)Bm_jV?p6IMTf7;557r2Y8QzBXg%m?BgM? zAO1jqdM=45nnm!^V2699vO2bG;+|kZ7^!DUX|8WfWTAlPO$06QIHm~99X)=@cM4*k z5^gR;gnoVd)oE=_e@j3>pfYh|)Voc(N@Z}|nQo-JVHjj#pa6<2Fsj$OdVUR;!JyFC zkHrPP6%4M=4LCf0x8rW-d$;%A*sU`@He$s~(%))DXH%PR2vkExxz!`%K{s08>IUjdF zm6z+eoE9G(-c>Cu>8Smf31$7JI1A-WxVp?l>gcXNaO`MwyA-46xvEwI*=}!}(%0Nn zHQJ3@L`7|`tL*^owD2uaZ`U*KCW#X-k;U~hX@kun0XN{dCTDN|Nvt=rmi`ApO1-wq z74NN+Kvccj3zKFppNd2(6?U?yX_2kp= zzI?=ohyBBDg$-Tq3ybO4LU^iw2a4PRkp(}-6BNXz;Isa@+5ADfI-qpCISFQg8XhPf zNtTCjG;4q!W`#Hhl_M2K?3cA7HH!~?XRDXj#g2*!xcH<(%05KKLI)udQ)0H?PD_7^ z<3 zO3%C5#36zXV#Ui?f) zj^;nP$Hd6n5}``#I5@mf^={{`t*p?c8Q6W*&D?T6i`D(|cZkYFQaQdFhrmz1XeF8+ zpIpV?io0=!qIsnQU2(=L0S@MG+ZB&Q{|SRtg@P8!h}Z6J-E}LDhNwMiI!~da?1r7N z$q+zxgPccNmtUVCp9@TVuGFaaUu2l#KPD>4cE{NtjvYF5A=hQpy1BX1^I=jkAh{W5 z8Q2@L!p4RUFt=U4$)(L9`%D{VJztWLoxOSf&2{YX%e^OmA>5X^+rU2em+bldTZT5x@4n2liytiM}Kg+8vRl zTR#0(NKYvDpUTiKW{+^Z`{z8S8qDp}N?=tK-1POkpHxUtgx#7o7t+b`+Ldc@07OOJ zH}D~^Wfg3~^mBg)ES$+@mlSBW;UW5h3p*@F?GI9wQrjtEZ=1&&=B(=4E4^&A!TaI}`N9v>7Gs_hbIxHuw-4n#K?H}_7ynZdOj>vr%f&!O)Q17U@ym|CJ?K7JBEUVH&7m1_4 zEMDQ9ME!E;Kx?dkF6r!1l}eb2;lK@-5EA}d`@nGi-_K1ST&U#(>fa7$IYBI~V0cp82n>h@Mw;f-pHrA9g_vR@N^?n4!Asa>kwFab@E!u* zoHugM{$K@@Ck&K_N$9^n7>G?_M$nai^}NgYn=U! zVPE0Qotql!H5-+D24b(#>vT7ZO8=Qo=VJ>#!~r*F+Z*$rP4%0uu(+%Eqv>dVI|;R) z)4_jiuoF+QZ}S$j`id@5mC`aU3<-ERxCb|ztE`RLOV1#L`l&4f;KSwb?+HzAxUX<2 z@u|7C@H)Ku&@aXwj;kZeyTb{2>7Lz%va`4A5kEMyJsZ;Ck`XTBb7#hCe1<`ae z3k#%1_kGh|hsDbevvH1vFG@`Hs)l~nBk-VT#KQ9cb@j!(ii&o;hBXUMu|kv^g%22} z{5+AOZ3xPs1j#4>qkaa3V#aMu2|Aj7Kk_aMo9QMGQ&~*aovDThIr`CFQhASk>=U_2 zpHX~#3Fgv(6*(~%vkv)3zipuz@Vfm7**Pfh!wH%lD)b5nzRvbkg#;x8kIVR@YRR|V z1yzN7t6v`&)6-=vb7Nc{Sn=V|R9YN}V*+X`BHg2K*i04xI+|=}sn!t-XWlv#ynu|P zV3#YhvTn;-)QI&5myxhVXt7@oxAA+wjqfV%7`+|YH1+s$y>R1b1(pZqB-dAZ_=JP? z603^55a~wor%LWB+YfzOuaA3Q>L;P|TUhU3I3V7%=WjF(S0h900x}gtT%%1~xRv(m zg2`7-`2k#@tk_J6!BR1I<7mEc{M=~afr7hAIDC8ANAbAZd_-%sA?EMTFMkNXdc7`w z#}{xwzCE74oaOC(@FlJl>iwu*PeD^Rn>rio7swJ!%#?`I$`Ll5dP#$4Ls8}XgYJ)( zJr0ovEvha~`4pyL4I^Viu-bPL!z!(z)?Rmx@7sR300gbXkbGv^oa8%>F<(D&`BU*J zV0Kz`Ii_#PYy9zK0DI%#r{t$JxbU8qLO$d?1l|un0&SvCmqEw|v#eS*jlCP($Zrwi zSx4=7>HACjLN_VvnNi^h*EOft`EL65sM(nZ#PHDYmBt`R@*=$2x$BD$o04hvI)Zpx zt+G3kz%Ltl(=*!KI-_|S)bq{p;k&bRp6|>9QqjNCGa^mbIKL2b$G7+ieEJB*@P+($ ztG(&-(;Zk~9~l;fBznl?)MZetWxXDaNT#k0uekzobJ<57CHr9;eP(us6Q=a5#mT7u z3YZ%eEEG9yC=OwS2A*${!@2CCV!`8S{C?1{fE@dy+n5J;t-wTJH`lN-g$QDMy7@`R z@RK^>{yw* zil_Fpnt~X1hR7}mjBrCKtvX5=vhO`qATvnv{sv za^S9(63NDS>_swLNoDx30Xm(uI)cb4=kdrNB;26&XxGev%V&w^7BXYJnGms^bUf&u z$usli0?8`9j-O0~JT8manylAN^D@_-@zOE<5OBSk$-_a1Zj?(^{}hZi%FGPVP;(`} zyu3J^rk`ni27$=zHax)*0xead%kKS=xeMPCqH1`P=V|b(XHYLHkGj8aJZzO&ysoKt zUG+z8Tv zD$&83Z7n%RqpSXkjqRD|@#Ij~{gQW3jDnqpKtu^q&xD6y&O^iMY!<-4DqdTE%yCJn z{L^V|esq%Hn-+?SwlYcSQ!B77_I9_UOH_?W+4P{DNd37y$CrSBI>+}!Xifz&f!a2A zbygxM!v^Kb7~Xer=7suCmqvLYGIC9X0PYOY5l#jgZe}@&ZiD&X@Hn*OOjFdb0jZ-l zg4o-(Px%32I~bRlqn`kA@XJF4>TOM} zpKFVZeuE?=#h%9v=^#q&TgLE3w!mtGH`mtf)Y(kEohzdQ&lhJlZWq>x^9w?C@%im!HcBfss*i?n4NNZD8~M(v8Vg(x_Z5hL?FKh@ z-Tu)D(nl}g%>g_(?WiCGcf@eXAsKHee#>lk4L8En^}dJs-*{{tY1yU8jsI@_s&w50A_wk@M!EH3-F`Nq zSCr(PG38RgNQiMJstq17>WiTZ2yGh~h#La{?)+2^=pNcYUw?o@v8(St*>rz+^5F20 z%`S~xf{sG_i*wW5diiZLPpCob{_js}KbNIP*Cj1<*gP^ZG&WjYNfqDD zuv35+nBvzcIwmGaei4#W@HY&&8BkaI$)n`|D-6>qF+C-WvAMeVRlRQi`j_TJpkz9aORvCDxd~{w!9eivYr6z2xDhqh*M*(Bc>~0}NyY`XdE*J3(UHLFm^@lBgtt zctVyCOo|R2)Mvy=ftA^1;eC}3Xs36*{#&1ATesux-`y`hS>{OF`VJeqro#{qXZNWE z@gtI4ADw!N+)nl zc=6&DuHCqo$+rU5kcwtD-pTW&$zlr#ajddjjO?!NiSI_rR$2*@`lLE7oRpY+2B zLpm+e9nh^C3_6H5yM5wf^nd>Zi;Rbk?cmf7o)88Yy)U)@W=#M|6i~l%;Bk0xzWeUbZ+W?MDd>_gOUs3s@X)3ZcZMD*RkCST zot4DPNzjF~{oo^3l1v!DQz&@2&3(@*fH=W1c=plCtR3S~IzZ#3Ti~dmn`=8>hxWzd z#*W#`!}YB9rPB-@DH8NY=Rte9hM?%}%j1yLoc&}?12*;*n7UQF-C?O*h2@6BXJiY; z(a;1xhsaj5Q+{2_F)M+yGyH-x-Yx?b)*^L?hOyG^LhVzkK+WpqvK+C#`-{VYDF1pN z!EQZtX+}WR4Y0>-MTI!bWGBTnePvOCo_Se3hOcSU!kfR@jj?o>)Du#L(3R^Fk~M;A zY>75n13NFe!a6$mnR{PuG)9^Qs*v%w;wJ3SJiZNUEE2?4DRGF|Us-2^=^Xfd zOiJj%`8!FksCeb7t$_kTT<#WE2R+8A(CmDWb3k)BwmYVXm@RSFEyg|*jcq^rY-|co zw4xKfa%k3iPFNYdg4JaAkYB-2fg`;^fF5r?KC)Zq9av(`T)R9@ovIfUFgimnZhf@~ zH92Ml*!zXSfcBxt*O=8LQVz?cnJJnH;!3RH`7!#i3+*k`?-EY1U%{-FSo3=FQ$Zd5DLPDL`au6 z+N}t=(H{rv-@3q7S%uq?mH)OA&`RJYiWstk6cP*=}IM=cITAEm|uFmUhD&_M9*Vq$vmg4Rh-T z*kpuK$uf=L!d7s}uj3*DA;PkXiX!oedrKzALju8Dpp5$UbI44z!N5w8jfv7%58IF2`gR=VwVFNFhn?qf9 z+i~UmRr^gAxQ|f8l$-`=-~pvb0cdFNV@AK=mJ1W8LYyw8d70X3^ZgOh#)AR0bm7M48^f?V ztvZFYfSDOl&v*Zyo1H$KM=j!qC!sBkLf8mANL$*2U_RiO)nw2~?&;WR)jcVV-48x< ziP&g*O0Ek9>PsIhJOQ&JL2ziC#oSM25a_6tj}#p-#H!5kW7Cg}75%_jLcZwDa&~_? z4BUxaIe#(Kufk7hJnx-p`nt9l3u;;aK7@0sv#`)du zrH3rCKnezrN_%kM!??Z$m3~2O*=c7-Y^g?jx`sIHYDvb^){f3N;X>q*AiberXu3=_ z5|6DU4Go9IbZie>O)~^z0R&$9HrJ5#O~4X5sU&vr66tmrsdBab4nC5g-vJj7_?^~P z1@u8Yf=F{+t1?xq6e8}aW%5LiZ)%vujuaK7n} zE5bmz=&(qJXx2vr^R}%ZeCBD`(2vhtF-*EGR~MO%Cf|9}IIS^B;!5X7lCl+uOh*c) z(t|r(Y4h#ZJA_(18h*z}phVfxPC~*$KzSt0rLW9tUTNFoQD(vVs-1=%Q^z$`|Jy4Z z#NeHNG+UKxaadF2rK9*tqSs=Vg^I8J=dG~4hVU-G&xrV|2!rLU&sXIyn3xWFvAzq)&xn_I@ z+;B7MKOa$j82Iqb!7PpkqyPYb^yeRzT6-7EWxXAPQ$yaL16mE90|wv-5@2|^+o9t| z@U6$K%`Q7wW%|IOo~!2oWxqBE#Cb+@xz?V_WB3RHk^(@lb3DuX9u{5y^?F*?Mv4|5+Gvr^Bf3BHjf6GWnTScs!*NRXX z!-|=(W1Eh zW)^6G`BBzbQBhHzH9;n~!(oUePQ9%w7S1ddhXET6rG)e)>zAMZv!;K@v<1X*LMF0x zLY@ArV>c2(0c?uO;R(c6a7zozjfFiq#kDhX+o-e;^=}2&OePajK}Q%G#2< zGr)fgVl0i9`UhxXkg zLyp&xcF%qHWnxOsaQyBNGM-uhRYY0E?}Qsl-#Smes4Z=A(-@RYE^K8^EY0ZJ7NEp7 zeALRjvB_wCU*^Aar-;}Gi8hirjwkWJckdU-YOGNESrBfe&JykGJve{M#Q5=KHd^=) zgcun~N5^RPaJBn0IT-?kaH580%5f!w3|O`(rDtw$6WoZsMK{>j*cZe{?4^qXJ*`3B5`z#e9{p~79L&zg976Q zqaOF%7YV^(YxUp3bRTu*VmBL1?WDAB{K47JY!Ori=|_BcvbH416e7R}Fj^R2hc(vc z@0T=I_2><&bSK-n%BCZb`1tQS;{nLPqFLO}_qa6plfoqaa3wxhQF;2Ol|H2{*a$jm zrk^e&@<(Jv5S6U6Vpjp3acf82s0XBWUv@EH0=<0$`G4P^K-<_jt*}!n9{3?aG$uZd z(P!z7ld~}tny!gC0UB;Ic z++}q-4J%&jk*)f|kC0<>KDOS$^naJL6$l%Cr+_xN{!|nw>e@L2g*T{=Mg)rr`%w+% zquM9zf^a(c1usEfw`{dkByA8vNzshk33?1Rwv4-b8_>Nqh56l$gf^v(FmT~1l=9@G zsTxnMHBowywq^1dcTeHUQ=m8#Svk*F*QmuJve~8qF>VxQ^i>T1qILW9*Sye`vhc73s6W=QQ5Ns_G<5|50>8_Dj@?RwNracv~ z<4GQz5dDR?l7iHB5KH0zE=LUB2@(y=@!oA4PwB2NsfAn656An+gowfS~vNqZwKTF~5Hp-7xGCwml5x zSyD`QV!FFi55SU5nRP=T<w|ykQDVq{=43$R?WFkSj*Bv_eq^FP)DLI^5-1ON|gU zPPe9`5O#J41TdfEAz5{x289;24oui3a7 zPN2uCSv)(d{82=_-c%^dn>^^VG4{-6@l3K2C;JzbQ}ku<*!{@=`fcqi4Ad_0l{L=M zd&eOoYSWcfrUOshrUrID^!LY5W2%ngIR{7kze=qCe2DMbU~a7i61&qv^BZeEE*pNo z-hSU$(Tbv4O^`%@#%EKBoy|J;r0`4dfh88Y=`?R?=fKpQQ3uIOE(WcfE93xY(j`!Y zfzqsQKBUonY6P+Zb4VVXFtnV&&fhcUx97bgVyw0LkNf?tpMU}Mb1fX#GS0+%N}+br zBv}(7@hI>^+vS~y)&^}be<Qk1t-}Ti8=ehL{ zfsbF=3b09AdF>#*)A#DxuwGD`kXOZY;ls2723By8k@+t^2|%$yS|ZYOt-5C!@;~H= z2*PNVcBD4cH0UhxbwFONr(y+7Fc1UED{GM0CD8+nmt9|owZH3z$x6`1*1#Nb#B%@q z%N1{HuXJ!CY>3QD#3TC0y=h{bPbl}F*`)2WmV_&x>a&iI_F>C$CcfA1JFa=CX|M-3 z=8^gCXfeO!cK#1bR~eR7)2)$`kd*EQ>F$sQDUpzF>F(YLNH+q~0s=~RcOxYr-Hp;M zeTMftf6U9vXV0@|&AMaVLmg!%ky*DePkS)S+hih3F7sLbIWO#$N!+N_FKFvc1RJqC z3@V51pY94(UAxePE7OJDpZ8y+j=pYP-KcaZCal=(uKFw`_mf8IvTrZi5$No}S&3mC z4k13<*nY<$cy8OXJO8pkAZnbD=3rLHJtKre*1U7zXm1jL#q{mnH|FEHS~8W)@adV`@SI*er1or&?B%RQI0B{CIS2)8ZtODcwPG6 zuW1ta!+#kdry|F1Ux$=4j;DX168R&R4glXQD5wc?>rBy?5?k&sa>wN!2GTI86~ad8 z%fQDWTBivy$RV3kaJ=tVT`)4ctqt9+yZ?!J%Q?YSVY&9@<{jms-}{+V%j;hs z9+osEl=i*P{D$0EX6kFpxUzfOLTH%W+}u7NEsx_0WnuDTVSi3&WRRyhnUePDA-xxO z8*W_Q5!m^O3>m9Fz{(@4%EZzhX*KO{#_F^%I-fO--cb+=qVy-!C`p}@g2Pfn95pXA zXn=jXdH33_?bDcRh->abREA?(x#Rrx%Qr30+t}r2!Mo^5 zbX5K#+tMn>@yjRfOA=;xP3FRJmPCO>fsRPB{v2*9j|NE0UQ;xrpQhKAzmxXIknRzS z`L`@Xc*yk^9!a&ldn+B4dxfMrc$dXKVD@8B>NLy!IN;_hqt^Jf_m zstc)7*z&%;Mh~L(iptfn5q^h{X98o7b!3;f9e-ge^Up9BqQ2JuLY%8ViTg@FU#O6C zsT^ha9G;Y$)b%-o@twxjH-l?9k%~_D6Z(G zrfXM`jMfy=r*3!&V~HI0JyFlh`p1Wt0mX9I9^hH?u@n~jGA?JWM8^c)E1`!3QfSXp zjBfDH%peXTh4(ozhvdr^Ai`rUnIMQ$ynP>C>pCl))2hoDz{4Ht!?A*YNxr+s=QV9s zy7rbtRnq3vUI1h9^h`^_p;1K_f?v*4P=4KGhvlMs>z2H`P-$u?-h=dUft`$w748s5 ztI73MVu7;scoachQBaX|@_>&Loa%EW9#~#XwE3^dO_gDSz&HO#Fzss&vS86y!XxPs ztysjSU>Yr}k~xP2-VUMu1&XJ)C;XF^OeJjEmznIi-fJg4%a-&8TSq+TUhQCM*$}3R z6i>!XF!fzr*PXbw;w#02@h?s2BB#fg$O;O0uEnG~9*>uteHeFtdWO!lpRw@pB<(lB zk<+7))R61Nq4@}N=Au8+HYa3mT2pATI#WnYjFcMm-zgalgjhnpXpqvL5^3^ma7j~_NKZ2{Hkqwm_&Au|(xZ0DDK_WF+9rY> zm+{(?rDFoM{jq5bRpa?!h2rY`TBC5~k3csKB|H10ICxgJq16HogwI}^49M~cILL%x z(qOps@jiGA{U2dkinvomX5}1fpLz43hxVMt(N6w>thRdvlojAzl3R+^g)PlR#PQsd z=nE2a!~&;;UL~c2v??(9sjI8UWo3;<^DPe;KHj_sGf=q}h|QK#um4^O zKh9oM9^pzGFE%*oxzByDU8qBoR-IocR}vzlMQLQV6rWoThFdoHaN1 z4MFCH@!V$oi?K^1ELVw6ia-jAAH zIzpmWAGf7}p-C(xo60==U(xg#lOM0xb)M1jOAB9Hr^)#F`TZVZWnfrMvngB42_>`U zX(v^%ugvl&naLc0Q`t=QKsXrD?e||c2-DNh0CT+8m-X#v0b@G~a{tos{5q^>V)~!K zjzE;BH3QCU9S+c=&kY8d;@jw}D%0+bi23;i-h_#?aGh|^-;^U1R?^Y5&MZ}<6wb`< z1`h`#wt9Dr9qk`)KSqdFDuVOXsVnCypU;g{WY;1Nj#EvqK}|R#es6PKTzgyz-bh9a z<4BMFGc-o}CRMWEB!1kLlop4EC=cT&Pr93ON~T<9C%WJd9sh78W{E~ssJ@4G#~Xl%T6Lf zCrK(U!RtVN>7lsF#^7$_7%~we+R{qXeooWADCH#8TH(XWjI+a^Ub+T03^?l{#E^Z* z#tF?Lz9k{A!z5S{^RUJ6HM>G1nr|FyHIofz^kS5=RNQ5K32srLq?)EFp6}3K5mAU~Q(f7&dI-Vzs_EP3DQbd`Gt!3-B?5jww%BFsLIVt3|0-RNUCJVW& ze}CUS8D@B`i$R5Tu3?fEtm<*pNpVQEN(=+tb(338q=DCBnFQ~>Y1f+Ssb=`F>RxcI z`2_DywdA2|N?VvUo3 z5XT&^#Y`*93zhsX3t?26%pm^0*By@`lX5r>#Fm)BK??oV4aNaeyY75%aB(>-2i}f~ z`Uob{Wxa6{7fmaprbqf=^X5y@ytn`TCaQ4bLMXT6i@?dCRQ2hEW$r}b+@M&w_q~4` zU1!i)S`@@Fa}CT(98m(g*H&{QS=Yy9$)iz=`$v81c?uUfxuLAEftORCfTf(oL6)rU zT00l%V=jYMsb*Qr>Cc8UE#~A=Ob^2j=6h%3xH{qng4GaEmxrsz3OE)?h#XP_@RUR& zy_d|fbzX?uV3q6G5aPw&l}cleOQ9Z#-4KiVY*D({;=?N3bb;m%oPp8HR}De_=ONZ_ zP*2x?x46HDrU=C*0t1XHDa|%1we94jgT`?slN2$o$Ni#rl`evP4KCq*_m>+IX_;nD z%IULcdjG6eDeSl`*wu4XK(Ba1gS3*W??cgDZbcv?D~-6QakWk>*=o69p6IVd^$EJs z{A=S^-ov-cuN7h!Xqe>_bnJwTyWmCdjwRjqXR&CZzscX064Z4^{nG1r9}kP@v%(aG zh#6twijP4ilEccx>;P&dbso3o-Ko07Cyw22hF`Q3JF}SPyo-Y zls5D@!65!>jU5+Fi2`Y}u+eM3>dbMF3ayiU+2~8qg=n4TboG`TTByz6AEl-FZ3RS2 zJJJp%(#55(i&^`9&e>zdu3*{PZy3cM#$*2ts`v*M1jjLJVoEtXJA0j%LtQ4dxkh)h z)`GvEKj>^n2M(^11Z=&4)yBnY_dkVMeHYa z`DSWq+Oy14JVL*lBJ0k$N#tOHF+dP=R6cc5s%g{Qzf1jvXMrp&{1zVuy1j*)o!~-d zI59q*rK#ap5u#Jm3qLC{?cPFk3RRql2_A40-_9$19G-w4$4O@RK3d##{nr&igCCb^ z?e%3bo`YlY)$o|)=jd+T5>0eI#9#N(cV0J+%JR6Ca|dC$FEunix|%h@izl2g5xI$f z3PO9vtHD!I-}Eub=jXL+H=gfpUGCvr@YO2%;oa5}vwqX(esU;dfA|G6uaI&mX<@5& z*-x5JFR%;*90+Fa9f-3@PjdU?psPv=W{%VxCk+i%jimGQ^WfVk5`l!ODo*#qMMC`) z20b!`v;>-qupS|*gJh_lwr1k@@190ra#j20t0l z+ruiE%}d$VZ3|dxXb9-d47jGmo`r4_qbX2XrrK`DA&}%s)%Etxo-4X?R%VH0kk%%8 ze(3fm^R+;ho$(8-^20?<@g0`NH|z@ZSfSLwjPi1zOgP8oDztMM_=a#NEabs(wlY85 zR7B@0;-qz_75vlm;41?PG&eVgT#pa`k!wsikyOZC3VHmzPAOL8Qlux*PN6e7<`{jsuuT|w})S@Zc_YyuivTw_@T z&Gp1zim`$^^SJ5KWxezTKf+49ceIxw{-TIWk=6J%cA2MB(>Vw780u6kZ6Ayw91|2Zr;t9mNtNx#W6vW*h=^|Z*Pz6(6?=2Ev$4(O$GcoiX`tgM`V8%-*N z7u)}GNkwByv)}p}S{63+kgv$UBK8@s6W*UayY&@S7P(NLn3%vOTd}X-aBkE&n33%v zO^-_sjF00*TP;c50l_~mNUur<1xap;zF-$%z0-VgB#5)&7OGx*T}^;ISy7bp7uM$C zO8Bw)D0KUa|BJf~PvR#~&o3}u+*2AF)Synj(y&iu);I?hPfLd%Wr<|1@1LU&HO>c` zRhqc)|FHp`B#i{9v4V7WhK*s`QqKWG%)M zc0roewA0nmO8dyY9xMJ%hKsU9uKhK|ukj2g54lPfmFCj3kZxc>T?77ohqEt%6riW{ zry6!bg$S1G;HZTUJ1LHjV4~6;iLBYfY-8n8i!i4*n!R~uENxUz(SHybD@Fep)XbaT zpsY3!N~kCRX?%m}Ew?iZ!yNY+VY3QP6oZt-FQ1;$z1=p%G9tdXyOI}Djb3GHIPjc{ zF%6hr9>%poaonGtj}ni4CakWA5+eSwLXqVS9eNpf{`mmgR+q0aa<3+xlrl!#_vbnb zh-WM{Gb|*h{J4knhL(Vjx{I8$o|cOUqZ*E>t7CG&C=n z8&{Rf@U5^=O;2y}u&s*uEZV_0$PjusO;Jqe9l^}868|0EV)Rv4YL;_xIhB@;Ew;G4 zEv@}-i)}cKr#Oh~wYa!=*PkHK;|3Ojvjz0166a?PqV9PXWIkbBh`8_kH;tkg)0Ay5 zJxlnOBEI8B$6=R8;7xP8m+5ucT=`B4kCca-RnmigMBWvlH94bzZ;I=cv<0+S(b?)Y z;BM@~|4O~}Za3rPuB8mIv@YV*jr?S${XQC)KTvHsD7|<{BxcaYlTUx<`8HUS7Te%X zTfI_8j0xBCA$gTb=_{=|FgE7k!rDL!rfM4=ZuU||e0Wjum{+UEL?aVyZKHi{VRdzN zwpgUKbg(TH#+pmn{bXbiU7+n@hm*idir=j1uy^%#`~ytPYoy--N%@v6@InU5i%SG%gvwOlnKf4gElC z3{@=4f$Y+ugS7u5;)x?p49sllerLjWklLB+{AOdzT#GoAmnV&t{ayw#GZxwbZ8{ffU(ioQFcW^rwIaBW#k{nlc2b7dX2W)PvIC)x!reFz;+HM0d@creD^Z z|{s4O9EW(7o_+ z{|c!~?3?5d+ZaFB+s3MYMTF)aF7>#uwGAKCub?-D^qLso4S=jrUIOi8@q{_UBU2T> zfUy|v)3r{-OK$k@$F(AC%cM1mBx*Pa=_62IPxwn8S3OmnQ~?*d4<9}VKi-{@@HG*5N|kwDB}7^Kea4ZUrQ5&zXTP#nn7Zx^d=59_&m zk_|cc+9o&soVcqsR@H<; zUW}a;M1wdp>7Uebs_7PnDfmPjc?v!hzLC^NizJU$Hhp|4X+-c}w!l z#2kiBGMd)vcv+s{59Ae4m|x{JeE*&jGA9b_Pi}FgAbD&?b;%?-FtCvcA)v17Snx`| zjx#e$7nwI^mQ?32hh)lQnd)9J6TIO3@bh!SnArWf+Op>c8XlX$@O-Teh{gCbaYBmz zeC2MNFBPQN)hM@={_>)tIjwQi?>DbL$vpB61(43;+8Z2+V};rNKf6AmdTm7W%{F^D zoSy+?iHJ@z`y(`R0|rvN{2dW*mG$OZ=8lrsBk6?!&uF^+D8>8qPw#a;`=mm*X=z&L z9kFv~*S9bjaE~+Z@&DsruYcveZ6rg_(ID$lHS&yaDoYfwgwOTBn1)LSU98wP8D9Xi zExriJpiTPcR-H|Kx!Jl8%6-=9zJue6hEC+E#p>wvf{lIb+wlAN)UT%y zi%{9?tBogN-d-I@s;XnszBBVY*xNZiYKFo*ZL#ZgB|i^1Y7wUXfp12oq>laC+jo1! zMn`g}H=#W+(~~5L&G)#=YVzrQ*Ba!gw`+hS4UQ59X6A3;cmU0gs+N|VfdLsX;DOvp zaDEPL4kk7}KHLhqwV|@L#38?=>xp;Q-JIo=B0~>tJZ#z{;4qO2-Fd~vw(~@W>8{-1 z0baiF>(>C_^##ZA?o2uP{mlh6A0IyGd}nM6wi<8a8cGR*5BiRwrX5(ln^N+)Ob)EV3B$mb&3`-bMgu>z_V-0=YRQnl|Uc zm9QYG5h0ddG(uHZcOivmvA{X)hsGfy9gGW1+sUL4WNC{cBeCgS+-O64>8E(vVB~gs zNp5d)JHhugwFZOaC{h75?rlW7gw;Rs;6u}kw+*APQTlu-T+36#ru`G++$oXHU36Y! zVlDna`s1}<{$1iQU^ll}fm47to(r}4ec>WD%gZ)(4LjV+(c$4JCc>A}SjAHj{Tq}_ zOpz@ukZ@IXwNsh>JhEpdAwHWRNt z`roU-8Y?J<>Cxh(1WcERm-PhytmOB+jpc)?FS_54xZDNNSUvTI{g@)u_DY?(A*p<( zX{yvqaDcfBja8TWq}GHYjyd4+lL85em)^vh&Iers6Qy7C)|DMmdTo!|x!LVODolg) zrF8t`{SoApy|cYdXG;d#*U~ERJS!>b)6mxXS}6H;IDOXcaSI48&Hx2zoHv&Rl2$g6 z{1=gXd{GXycAGLrbYb`(!-3KF+_M>T*bMn;7TvhOczOHW+}yyCbiONGr+QoVb-Hyc zxD20z=zl>uc&GXC*LJk-%DU9w2y_-Vb+Ypu4iZqWte{O5dF$sUI8a zA)$whh!o81%tZQFATwRIG61ppUk}-f!N?^@$rr(C<8)X{I_AGKP#Xe_VNT*-J6EaWY`AmpSmzOQWrM*byxdJ&OKkTbdOE+qDF5fc6ewf&MH0GUvQ7V|gci;95l zw(mn<`_12C&(`I(H_C}H#E4dfFn>BmVA?(J?1)-Ax5*YttNN8@2lQ?A zj-$Np2s7313%c4!Yrem24O5f>6t^ z1>54V50Q@eqs3dT&eL_NK_IG9g7Jy_R%@Citn(cvC>CmC@@#E zd=A6?MV&Y0YvT$=hG){!B4+lsZdV@tLwAyC!W&(7z?2{umUH6$<(B!H z0<6x?qRW`w4g+GH-9jIAtZ?AM!J&Gw>KTzt6agge?JWocQscJgEV7mO$NWhsOgtA@ zUre|^+j*wQ??YxfnjybaUhCZ@8T00nc{#ULf>%(<1ZYrip*Gkm-T$|&=+JD4f=+<#O%C_hJOdZ+$ z0a>^kHtS$IX@7`V#Dkv;Ty@04W8wB})u(!{o!n^e$;$h~;?+qdvQ`3(as2|YMgv-u zsYI_4o4sqGI}}5OArM<(wW$o`^~uT0cOJNdv?W+F-{Vg7e$Y}eyirg9O*BIUHfdsk z)$ge(4xh_?bdB+@HFl3BH~c3d1afZvMtZx7g&vwJ1!0Guwp~eEE3=Ft<>;!3OCN=L z1W1iq;l1zZC&8~;&D5i+ zslEzDrkBnl%wmfHuPrPFUXqB0dHQ)3&h5=Q6T|<<_RGlYxQQ+FJP+x&WV6GJ$i_(J;U$zveNU!1k4E)ejW$=397J~ zq!T7n(OWr8p1~J#msWLbUQ%5zD=9JS3`B66r0DmuUtoTG)A?mXl-y_=cZIIp7Dv=j z4b~W!#Xw7XQdJ{!{%25$=cU2f?Bny6=TZIN5yTMqUz(N)L6i}FnbOL03~&0g<=syx zgbC+nOL;R6aUQ&{<%%xt=&K$J`+JCP;6WnHI8&nTU*v}l&iY5_zaKh z(s2WD*Ec{;>SRM0e6Hy=x)RABGL-4jLxVn{;se*BB!I^j*?zn#V)w3HUN&5nBf&KC z;8+7G1Rnwj@EZ|T43<}qVdovb%j>Zp7g%YjGz*g6Jek-6 zGb2I)gnNG4nWY1#o)~&OfZ#*B#ogR^hI4G4S zy(pkzVtqI-6sr|L4DE(G@2lxAWMgy|Vy8 z1x_k@ca*6&^Zgt1IsQ{w724XbV(2P}u#5?1lqdx9iE9+OG!RudY!!_Wmb96C4;Au2 zZpSMwR_^fIy$%mBO-TF1*7W4~^ek!hf5C}=)+?Q9O-cBvAQzeH@#?A&`9*e=Iyby{ zT`u5qTz-OKKQZ^hVj)S+zWlxKMdIv%w&FDc0*=S*)9`=wK@jpazF{z5iPHv4ea@$4 z7~0@fMap|9s_{HsfPC}ZK9&}1xY0hcw<||7Gbgmhv=X)h!Z;`=^?(ct ze@X9Ngx<{5un{8!La;EE3#%1e#&h0=t=u1aIGvUyB_%l-KW@NJF1SzVRf`bvqpmJG zEPousrzq(~Dz?PJSisR8PiwW)m{jE^^)VMs5ru9Lcy8;A6^6Q!<73UP0t%>h8L243 zzcM|e8E1g|EcHwtJ5HKIViqhCWh5*fSR_LDLq`kFf1h938eVV^oNcI(sRTVO6#et2 z!)0qmfIoMlU+p>bda+}!?qG=a%2VIw&!U8U9dH}_1d&h}OB&af<*6XLrQOd_6-`m%dI+{sdy(pbRG(rZG=!^3k} zEp*rr1eVGDFMk5f+KH!}l2SA;!d!!sX?gV7!|jp9$$GETI^zM0Iff%ZbZa5RU$`uk z7f-;hetG%g$oA;iUZRKL(RniCGjypIU;{nC0F+JpclO2UF1F-4omFw#i9wam0Esh7 z%)SYxSxp?dII66?F7^uyodhZ=(vz}uL)s0$;2M^MFb!<1DfS(|v(W8-*)XG>a?V1y zriZ@hGJE68ez}TIViTilYQx3X><8z#bk=rEAN(8c=e|nJ558!zw!(psIyX+|HoW-j zD<1*cq0ZU(?mRo*W{`lJzV+sVz?(%0A^9fsl=PE(RIj7>cJ{5ur9ij&4+GSrua8O6 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

yLrh1+7Ns56#BT6qHu|-Yaz8 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 Date: Sun, 6 Dec 2020 09:49:57 +0100 Subject: [PATCH 16/97] AbstractGuiGame: only create Timer when needed, and destroy again after game end --- .../java/forge/screens/match/CMatchUI.java | 1 + .../forge/screens/match/MatchController.java | 1 + .../java/forge/match/AbstractGuiGame.java | 23 +++++++++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java index cb49ced38f4..a505d104ac5 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java @@ -1025,6 +1025,7 @@ public final class CMatchUI @Override public void afterGameEnd() { + super.afterGameEnd(); Singletons.getView().getLpnDocument().remove(targetingOverlay.getPanel()); FThreads.invokeInEdtNowOrLater(new Runnable() { @Override public void run() { diff --git a/forge-gui-mobile/src/forge/screens/match/MatchController.java b/forge-gui-mobile/src/forge/screens/match/MatchController.java index 7471e651775..51c1ffafe75 100644 --- a/forge-gui-mobile/src/forge/screens/match/MatchController.java +++ b/forge-gui-mobile/src/forge/screens/match/MatchController.java @@ -445,6 +445,7 @@ public class MatchController extends AbstractGuiGame { @Override public void afterGameEnd() { + super.afterGameEnd(); Forge.back(); //view = null; } diff --git a/forge-gui/src/main/java/forge/match/AbstractGuiGame.java b/forge-gui/src/main/java/forge/match/AbstractGuiGame.java index fbff635cf47..dd6490bebb3 100644 --- a/forge-gui/src/main/java/forge/match/AbstractGuiGame.java +++ b/forge-gui/src/main/java/forge/match/AbstractGuiGame.java @@ -188,7 +188,12 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards { return true; } if(spectator!=null) { //workaround fix!! this is needed on above code or it will - gameControllers.remove(spectator); //bug the UI! remove spectator here since its must not be here... + for (Map.Entry e : gameControllers.entrySet()) { + if (e.getValue().equals(spectator)) { + gameControllers.remove(e.getKey()); + break; + } + } return true; } try{ @@ -368,11 +373,14 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards { return autoPassUntilEndOfTurn.contains(player); } - private final Timer awaitNextInputTimer = new Timer(); + private Timer awaitNextInputTimer; private TimerTask awaitNextInputTask; @Override public final void awaitNextInput() { + if (awaitNextInputTimer == null) { + awaitNextInputTimer = new Timer("awaitNextInputTimer Game:" + this.gameView.getId() + " Player:" + this.currentPlayer.getLobbyPlayerName()); + } //delay updating prompt to await next input briefly so buttons don't flicker disabled then enabled awaitNextInputTask = new TimerTask() { @Override @@ -400,6 +408,9 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards { @Override public final void cancelAwaitNextInput() { + if (awaitNextInputTimer == null) { + return; + } synchronized (awaitNextInputTimer) { //ensure task doesn't reset awaitNextInputTask during this block if (awaitNextInputTask != null) { try { @@ -725,5 +736,13 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards { public void handleLandPlayed(Card land, Zone zone) { } + + @Override + public void afterGameEnd() { + if (awaitNextInputTimer != null) { + awaitNextInputTimer.cancel(); + awaitNextInputTimer = null; + } + } // End of Choice code } From c9500859fe292a9bd94a45894977b9c17883c7dd Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Sun, 6 Dec 2020 17:51:15 +0100 Subject: [PATCH 17/97] RelaceDamage: fix DamageTarget check using Replaced values --- .../forge/game/replacement/ReplaceDamage.java | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceDamage.java b/forge-game/src/main/java/forge/game/replacement/ReplaceDamage.java index a5ce0550ef2..c0d8e1ebcb0 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplaceDamage.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceDamage.java @@ -17,6 +17,7 @@ */ package forge.game.replacement; +import forge.game.Game; import forge.game.GameEntity; import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; @@ -48,6 +49,7 @@ public class ReplaceDamage extends ReplacementEffect { */ @Override public boolean canReplace(Map runParams) { + final Game game = getHostCard().getGame(); if (!(runParams.containsKey(AbilityKey.Prevention) == (hasParam("PreventionEffect") || hasParam("Prevent")))) { return false; @@ -128,17 +130,33 @@ public class ReplaceDamage extends ReplacementEffect { } // check for DamageRedirection, the Thing where the damage is redirected to must be a creature or planeswalker or a player String def = getParam("DamageTarget"); - for (Player p : AbilityUtils.getDefinedPlayers(hostCard, def, null)) { - if (!p.getGame().getPlayers().contains(p)) { + if (def.startsWith("Replaced")) { + // this can't work with the Defined below because the replaced objects aren't set to a possible SA yet + if (def.equals("ReplacedSourceController")) { + Card source = (Card) runParams.get(AbilityKey.DamageSource); + if (!game.getPlayers().contains(source.getController())) { + return false; + } + } else if (def.equals("ReplacedTargetController")) { + if (!(affected instanceof Card) || !game.getPlayers().contains(((Card) affected).getController())) { + return false; + } + } else { return false; } - } - for (Card c : AbilityUtils.getDefinedCards(hostCard, def, null)) { - if (!c.isCreature() && !c.isPlaneswalker()) { - return false; + } else { + for (Player p : AbilityUtils.getDefinedPlayers(getHostCard(), def, null)) { + if (!game.getPlayers().contains(p)) { + return false; + } } - if (!c.isInPlay()) { - return false; + for (Card c : AbilityUtils.getDefinedCards(getHostCard(), def, null)) { + if (!c.isCreature() && !c.isPlaneswalker()) { + return false; + } + if (!c.isInPlay()) { + return false; + } } } } From 9907150d8a0060eae9fdb5b9d153d6212df73e76 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Sun, 6 Dec 2020 22:18:03 -0500 Subject: [PATCH 18/97] thief_of_blood.txt needs ETB$ True --- forge-gui/res/cardsfolder/t/thief_of_blood.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/forge-gui/res/cardsfolder/t/thief_of_blood.txt b/forge-gui/res/cardsfolder/t/thief_of_blood.txt index d561db94bdf..dad73b276bd 100644 --- a/forge-gui/res/cardsfolder/t/thief_of_blood.txt +++ b/forge-gui/res/cardsfolder/t/thief_of_blood.txt @@ -4,10 +4,10 @@ Types:Creature Vampire PT:1/1 K:Flying K:ETBReplacement:Other:DBRemoveCounterAll -SVar:DBRemoveCounterAll:DB$ RemoveCounterAll | ValidCards$ Permanent | AllCounterTypes$ True | StackDescription$ SpellDescription | SubAbility$ DBPutCounters| RememberAmount$ True | SpellDescription$ As CARDNAME enters the battlefield, remove all counters from all permanents. CARDNAME enters the battlefield with a +1/+1 counter on it for each counter removed this way. -SVar:DBPutCounters:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ X | SubAbility$ DBCleanup +SVar:DBRemoveCounterAll:DB$ RemoveCounterAll | ValidCards$ Permanent | AllCounterTypes$ True | StackDescription$ SpellDescription | SubAbility$ DBPutCounters | RememberAmount$ True | SpellDescription$ As CARDNAME enters the battlefield, remove all counters from all permanents. CARDNAME enters the battlefield with a +1/+1 counter on it for each counter removed this way. +SVar:DBPutCounters:DB$ PutCounter | ETB$ True | Defined$ Self | CounterType$ P1P1 | CounterNum$ X | References$ X | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:X:Count$ChosenNumber AI:RemoveDeck:Random -SVar:Picture:http://www.wizards.com/global/images/magic/general/thief_of_blood.jpg +DeckHas:Ability$Counters Oracle:Flying\nAs Thief of Blood enters the battlefield, remove all counters from all permanents. Thief of Blood enters the battlefield with a +1/+1 counter on it for each counter removed this way. From c5ec4994c0624a0bf96e3d2c7d3febd49bb01792 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Sun, 6 Dec 2020 22:27:35 -0500 Subject: [PATCH 19/97] plague_reaver.txt +DelayTriggerDefinedPlayer$ --- forge-gui/res/cardsfolder/upcoming/plague_reaver.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge-gui/res/cardsfolder/upcoming/plague_reaver.txt b/forge-gui/res/cardsfolder/upcoming/plague_reaver.txt index 95414bb8e13..5a0dd84b79d 100644 --- a/forge-gui/res/cardsfolder/upcoming/plague_reaver.txt +++ b/forge-gui/res/cardsfolder/upcoming/plague_reaver.txt @@ -5,7 +5,7 @@ PT:6/5 T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ SacAllOthers | TriggerDescription$ At the beginning of your end step, sacrifice each other creature you control. SVar:SacAllOthers:DB$ SacrificeAll | ValidCards$ Creature.Other+YouCtrl A:AB$ Pump | Cost$ Discard<2/Card> Sac<1/CARDNAME> | ValidTgts$ Opponent | TgtPrompt$ Select target opponent | RememberTargets$ True | SubAbility$ DBDelayTrig | StackDescription$ Return CARDNAME to the battlefield under {p:Targeted}'s control at the beginning of their next upkeep. | SpellDescription$ Choose target opponent. Return CARDNAME to the battlefield under that player's control at the beginning of their next upkeep. -SVar:DBDelayTrig:DB$ DelayedTrigger | TriggerZones$ Graveyard | Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Player.IsRemembered | RememberObjects$ Remembered | Execute$ DBChange | StackDescription$ None | TriggerDescription$ Return CARDNAME to the battlefield under that player’s control at the beginning of their next upkeep. +SVar:DBDelayTrig:DB$ DelayedTrigger | TriggerZones$ Graveyard | Mode$ Phase | Phase$ Upkeep | DelayedTriggerDefinedPlayer$ Remembered | RememberObjects$ Remembered | Execute$ DBChange | StackDescription$ None | TriggerDescription$ Return CARDNAME to the battlefield under that player’s control at the beginning of their next upkeep. SVar:DBChange:DB$ ChangeZone | Defined$ Self | Origin$ Graveyard | Destination$ Battlefield | GainControl$ True | NewController$ DelayTriggerRemembered AI:RemoveDeck:All DeckHas:Ability$Discard & Ability$Sacrifice From 3a7e3cb9931554e63bc0a19f5962c1ef2da4271d Mon Sep 17 00:00:00 2001 From: Northmoc Date: Sun, 6 Dec 2020 23:00:01 -0500 Subject: [PATCH 20/97] maze_of_ith.txt cleanup --- forge-gui/res/cardsfolder/m/maze_of_ith.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/forge-gui/res/cardsfolder/m/maze_of_ith.txt b/forge-gui/res/cardsfolder/m/maze_of_ith.txt index 0dbf163a7a8..2eaa3a91201 100644 --- a/forge-gui/res/cardsfolder/m/maze_of_ith.txt +++ b/forge-gui/res/cardsfolder/m/maze_of_ith.txt @@ -1,7 +1,6 @@ Name:Maze of Ith ManaCost:no cost Types:Land -A:AB$ Pump | Cost$ T | ValidTgts$ Creature.attacking | TgtPrompt$ Select target attacking creature | KW$ Prevent all combat damage that would be dealt to and dealt by CARDNAME. | SubAbility$ DBUntap | IsCurse$ True | SpellDescription$ Untap target attacking creature. Prevent all combat damage that would be dealt to and dealt by that creature this turn. -SVar:DBUntap:DB$Untap | Defined$ Targeted -SVar:Picture:http://www.wizards.com/global/images/magic/general/maze_of_ith.jpg +A:AB$ Untap | Cost$ T | ValidTgts$ Creature.attacking | TgtPrompt$ Select target attacking creature | SubAbility$ DBPump | IsCurse$ True | StackDescription$ Untap {c:Targeted}. | SpellDescription$ Untap target attacking creature. Prevent all combat damage that would be dealt to and dealt by that creature this turn. +SVar:DBPump:DB$ Pump | Defined$ Targeted | KW$ Prevent all combat damage that would be dealt to and dealt by CARDNAME. | StackDescription$ Prevent all combat damage that would be dealt to and dealt by that creature this turn. Oracle:{T}: Untap target attacking creature. Prevent all combat damage that would be dealt to and dealt by that creature this turn. From ff7638e2fc03e9d4c0753fed3b4d3d2ea432829f Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Mon, 7 Dec 2020 12:14:16 +0800 Subject: [PATCH 21/97] [Mobile] Fix annoying overlay between Quest Commander matches - Only load the overlay when generating the Quest outside the match/duels --- .../forge/screens/match/winlose/QuestWinLose.java | 14 ++++++++++++++ .../src/forge/screens/quest/QuestDuelsScreen.java | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/forge-gui-mobile/src/forge/screens/match/winlose/QuestWinLose.java b/forge-gui-mobile/src/forge/screens/match/winlose/QuestWinLose.java index 21036a445a8..56faf35e470 100644 --- a/forge-gui-mobile/src/forge/screens/match/winlose/QuestWinLose.java +++ b/forge-gui-mobile/src/forge/screens/match/winlose/QuestWinLose.java @@ -18,6 +18,7 @@ package forge.screens.match.winlose; import forge.game.GameView; import forge.quest.QuestWinLoseController; +import forge.screens.home.HomeScreen; /** *

@@ -44,6 +45,10 @@ public class QuestWinLose extends ControlWinLose { @Override public final void showRewards() { + //set loading overlay again + if (HomeScreen.instance.getQuestWorld().contains("XandomX")) { + HomeScreen.instance.updateQuestWorld(HomeScreen.instance.getQuestWorld().replace("XandomX","Random")); + } controller.showRewards(); } @@ -60,4 +65,13 @@ public class QuestWinLose extends ControlWinLose { controller.actionOnQuit(); super.actionOnQuit(); } + + @Override + public void actionOnContinue() { + //prevent loading overlay to show on continuing match... TODO: refactor this to a better implementation + if (HomeScreen.instance.getQuestWorld().contains("Random")) { + HomeScreen.instance.updateQuestWorld(HomeScreen.instance.getQuestWorld().replace("Random","XandomX")); + } + super.actionOnContinue(); + } } diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestDuelsScreen.java b/forge-gui-mobile/src/forge/screens/quest/QuestDuelsScreen.java index b9edf03ead6..4987202c0de 100644 --- a/forge-gui-mobile/src/forge/screens/quest/QuestDuelsScreen.java +++ b/forge-gui-mobile/src/forge/screens/quest/QuestDuelsScreen.java @@ -75,7 +75,7 @@ public class QuestDuelsScreen extends QuestLaunchScreen { FThreads.invokeInEdtLater(new Runnable() { @Override public void run() { - LoadingOverlay.show("Loading Random Quest", new Runnable() { + LoadingOverlay.show(Localizer.getInstance().getMessage("lblLoadingCurrentQuest"), new Runnable() { @Override public void run() { generateDuels(); From 37461aa3e54ca0021a65bb86cda014bec954b1eb Mon Sep 17 00:00:00 2001 From: Northmoc Date: Sun, 6 Dec 2020 23:02:39 -0500 Subject: [PATCH 22/97] raiding_party.txt and support --- .../game/ability/effects/ChooseCardEffect.java | 5 +++++ forge-gui/res/cardsfolder/r/raiding_party.txt | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 forge-gui/res/cardsfolder/r/raiding_party.txt diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java index 3d55ced65bc..2b3e8aa16e2 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java @@ -135,5 +135,10 @@ public class ChooseCardEffect extends SpellAbilityEffect { host.removeRemembered(rem); } } + if (sa.hasParam("ImprintChosen")) { + for (final Card imp : chosen) { + host.addImprintedCard(imp); + } + } } } diff --git a/forge-gui/res/cardsfolder/r/raiding_party.txt b/forge-gui/res/cardsfolder/r/raiding_party.txt new file mode 100644 index 00000000000..7c1a88b1095 --- /dev/null +++ b/forge-gui/res/cardsfolder/r/raiding_party.txt @@ -0,0 +1,17 @@ +Name:Raiding Party +ManaCost:2 R +Types:Enchantment +S:Mode$ CantTarget | ValidCard$ Card.Self | ValidSource$ Card.White | Description$ CARDNAME can't be the target of white spells or abilities from white sources. +A:AB$ RepeatEach | Cost$ Sac<1/Orc/Orc> | CostDesc$ Sacrifice an Orc: | RepeatPlayers$ Player | RepeatSubAbility$ ChooseCardsToTap | SubAbility$ DBDestroy | SpellDescription$ Each player may tap any number of untapped white creatures they control. For each creature tapped this way, that player chooses up to two Plains. Then destroy all Plains that weren’t chosen this way by any player. +SVar:ChooseCardsToTap:DB$ ChooseCard | Defined$ Remembered | MinAmount$ 0 | Amount$ NumCreatures | References$ NumCreatures | Choices$ Creature.untapped+White+RememberedPlayerCtrl | ChoiceTitle$ Choose any number of untapped white creatures you control | ChoiceZone$ Battlefield | RememberChosen$ True | SubAbility$ DBTap +SVar:DBTap:DB$ Tap | Defined$ Remembered | SubAbility$ ChoosePlainsToSave +SVar:ChoosePlainsToSave:DB$ ChooseCard | Defined$ Remembered | MinAmount$ 0 | Amount$ TappedXTwo | References$ TappedXTwo | Choices$ Plains | ChoiceTitle$ Choose up to two Plains for each creature tapped | ChoiceZone$ Battlefield | ImprintChosen$ True | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True +SVar:DBDestroy:DB$ DestroyAll | ValidCards$ Plains.IsNotImprinted | SubAbility$ DBCleanImp | StackDescription$ None +SVar:DBCleanImp:DB$ Cleanup | ClearImprinted$ True +SVar:NumCreatures:Count$Valid Creature.untapped+White+RememberedPlayerCtrl +SVar:TappedXTwo:Count$Valid Creature.IsRemembered/Times.2 +AI:RemoveDeck:Random +SVar:NeedsToPlay:Plains.OppCtrl +DeckNeeds:Type$Orc +Oracle:Raiding Party can’t be the target of white spells or abilities from white sources.\nSacrifice an Orc: Each player may tap any number of untapped white creatures they control. For each creature tapped this way, that player chooses up to two Plains. Then destroy all Plains that weren’t chosen this way by any player. From f9a601893c57b4e6a453a2e07f7ff5cc3e917ca9 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Mon, 7 Dec 2020 09:00:54 -0500 Subject: [PATCH 23/97] preferred_selection.txt --- forge-gui/res/cardsfolder/p/preferred_selection.txt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 forge-gui/res/cardsfolder/p/preferred_selection.txt diff --git a/forge-gui/res/cardsfolder/p/preferred_selection.txt b/forge-gui/res/cardsfolder/p/preferred_selection.txt new file mode 100644 index 00000000000..ef24876aca2 --- /dev/null +++ b/forge-gui/res/cardsfolder/p/preferred_selection.txt @@ -0,0 +1,9 @@ +Name:Preferred Selection +ManaCost:2 G G +Types:Enchantment +T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigLook | TriggerDescription$ At the beginning of your upkeep, look at the top two cards of your library. You may sacrifice CARDNAME and pay {2}{G}{G}. If you do, put one of those cards into your hand. If you don’t, put one of those cards on the bottom of your library. +SVar:TrigLook:DB$ PeekAndReveal | Defined$ You | PeekAmount$ 2 | NoReveal$ True | SubAbility$ DBBottom +SVar:DBBottom:DB$ Dig | UnlessCost$ Sac<1/CARDNAME> 2 G G | UnlessPayer$ You | UnlessResolveSubs$ WhenPaid | SubAbility$ DBPutHand | DigNum$ 2 | ChangeNum$ 1 | DestinationZone$ Library | DestinationZone2$ Library | LibraryPosition$ -1 | LibraryPosition2$ 0 | ChangeValid$ Card +SVar:DBPutHand:DB$ Dig | UnlessSwitched$ True | DigNum$ 2 | ChangeNum$ 1 | DestinationZone$ Hand | DestinationZone2$ Library | LibraryPosition2$ 0 | ChangeValid$ Card +DeckHas:Ability$Sacrifice +Oracle:At the beginning of your upkeep, look at the top two cards of your library. You may sacrifice Preferred Selection and pay {2}{G}{G}. If you do, put one of those cards into your hand. If you don’t, put one of those cards on the bottom of your library. From 0216b52d1c5ab1b6a9c14b0496785d1c667747e9 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Mon, 7 Dec 2020 09:07:35 -0500 Subject: [PATCH 24/97] add logic --- forge-gui/res/cardsfolder/p/preferred_selection.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/forge-gui/res/cardsfolder/p/preferred_selection.txt b/forge-gui/res/cardsfolder/p/preferred_selection.txt index ef24876aca2..e956cac9394 100644 --- a/forge-gui/res/cardsfolder/p/preferred_selection.txt +++ b/forge-gui/res/cardsfolder/p/preferred_selection.txt @@ -3,7 +3,7 @@ ManaCost:2 G G Types:Enchantment T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigLook | TriggerDescription$ At the beginning of your upkeep, look at the top two cards of your library. You may sacrifice CARDNAME and pay {2}{G}{G}. If you do, put one of those cards into your hand. If you don’t, put one of those cards on the bottom of your library. SVar:TrigLook:DB$ PeekAndReveal | Defined$ You | PeekAmount$ 2 | NoReveal$ True | SubAbility$ DBBottom -SVar:DBBottom:DB$ Dig | UnlessCost$ Sac<1/CARDNAME> 2 G G | UnlessPayer$ You | UnlessResolveSubs$ WhenPaid | SubAbility$ DBPutHand | DigNum$ 2 | ChangeNum$ 1 | DestinationZone$ Library | DestinationZone2$ Library | LibraryPosition$ -1 | LibraryPosition2$ 0 | ChangeValid$ Card -SVar:DBPutHand:DB$ Dig | UnlessSwitched$ True | DigNum$ 2 | ChangeNum$ 1 | DestinationZone$ Hand | DestinationZone2$ Library | LibraryPosition2$ 0 | ChangeValid$ Card +SVar:DBBottom:DB$ Dig | UnlessCost$ Sac<1/CARDNAME> 2 G G | UnlessPayer$ You | UnlessResolveSubs$ WhenPaid | UnlessAI$ Never | SubAbility$ DBPutHand | DigNum$ 2 | ChangeNum$ 1 | AILogic$ WorstCard | DestinationZone$ Library | DestinationZone2$ Library | LibraryPosition$ -1 | LibraryPosition2$ 0 | ChangeValid$ Card +SVar:DBPutHand:DB$ Dig | DigNum$ 2 | ChangeNum$ 1 | DestinationZone$ Hand | DestinationZone2$ Library | LibraryPosition2$ 0 | ChangeValid$ Card DeckHas:Ability$Sacrifice Oracle:At the beginning of your upkeep, look at the top two cards of your library. You may sacrifice Preferred Selection and pay {2}{G}{G}. If you do, put one of those cards into your hand. If you don’t, put one of those cards on the bottom of your library. From 0082bb9c77ad303a43a7983c44aecc0ae0f9c1a4 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Mon, 7 Dec 2020 09:31:51 -0500 Subject: [PATCH 25/97] congregation_at_dawn.txt typo fix --- forge-gui/res/cardsfolder/c/congregation_at_dawn.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/forge-gui/res/cardsfolder/c/congregation_at_dawn.txt b/forge-gui/res/cardsfolder/c/congregation_at_dawn.txt index a985ecc886b..69971054006 100644 --- a/forge-gui/res/cardsfolder/c/congregation_at_dawn.txt +++ b/forge-gui/res/cardsfolder/c/congregation_at_dawn.txt @@ -1,6 +1,5 @@ Name:Congregation at Dawn ManaCost:G G W Types:Instant -A:SP$ ChangeZone | Cost$ G G W | Origin$ Library | Destination$ Library | LibraryPosition$ 0 | ChangeType$ Creature | ChangeNum$ 3 | SpellDescription$ Search your library for up to three creature cards and reveal them. Shuffle you library, then put those cards on top of it in any order. -SVar:Picture:http://www.wizards.com/global/images/magic/general/congregation_at_dawn.jpg +A:SP$ ChangeZone | Cost$ G G W | Origin$ Library | Destination$ Library | LibraryPosition$ 0 | ChangeType$ Creature | ChangeNum$ 3 | SpellDescription$ Search your library for up to three creature cards and reveal them. Shuffle your library, then put those cards on top of it in any order. Oracle:Search your library for up to three creature cards and reveal them. Shuffle your library, then put those cards on top of it in any order. From f1767a57a30aeba5d0cfbccc57de63bc6dc58a56 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Mon, 7 Dec 2020 23:01:15 +0800 Subject: [PATCH 26/97] try to fix StackOverflow --- .../main/java/forge/game/card/CardView.java | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/forge-game/src/main/java/forge/game/card/CardView.java b/forge-game/src/main/java/forge/game/card/CardView.java index f2d162494e8..a6487422fc2 100644 --- a/forge-game/src/main/java/forge/game/card/CardView.java +++ b/forge-game/src/main/java/forge/game/card/CardView.java @@ -392,6 +392,7 @@ public class CardView extends GameEntityView { if (viewers == null || Iterables.isEmpty(viewers)) { return true; } return Iterables.any(viewers, new Predicate() { + @Override public final boolean apply(final PlayerView input) { return canBeShownTo(input); } @@ -456,14 +457,17 @@ public class CardView extends GameEntityView { } public boolean canFaceDownBeShownToAny(final Iterable viewers) { + if (viewers == null || Iterables.isEmpty(viewers)) { return true; } + return Iterables.any(viewers, new Predicate() { - @Override public final boolean apply(final PlayerView input) { - return canFaceDownBeShownTo(input); + @Override + public final boolean apply(final PlayerView input) { + return canFaceDownBeShownTo(input, false); } }); } - private boolean canFaceDownBeShownTo(final PlayerView viewer) { + private boolean canFaceDownBeShownTo(final PlayerView viewer, boolean skip) { if (!isFaceDown()) { return true; } @@ -472,13 +476,15 @@ public class CardView extends GameEntityView { if (mayPlayerLook(viewer)) { return true; } - final PlayerView controller = getController(); - //if viewer is controlled by another player, also check if face can be shown to that player - final PlayerView mindSlaveMaster = viewer.getMindSlaveMaster(); - if (mindSlaveMaster != null && mindSlaveMaster != controller && canFaceDownBeShownTo(mindSlaveMaster)) { - return true; + if (!skip) { + //if viewer is controlled by another player, also check if face can be shown to that player + final PlayerView mindSlaveMaster = viewer.getMindSlaveMaster(); + if (mindSlaveMaster != null) { + return canFaceDownBeShownTo(mindSlaveMaster, true); + } } - return isInZone(EnumSet.of(ZoneType.Battlefield, ZoneType.Stack, ZoneType.Sideboard)) && controller.equals(viewer); + + return isInZone(EnumSet.of(ZoneType.Battlefield, ZoneType.Stack, ZoneType.Sideboard)) && getController().equals(viewer); } public FCollectionView getEncodedCards() { From 321787298e4ccc91ad2771e373825816aea34e90 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Tue, 8 Dec 2020 03:42:55 +0800 Subject: [PATCH 27/97] Fix Parallax Wave - fix combo with Opalescence --- forge-gui/res/cardsfolder/p/parallax_wave.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/forge-gui/res/cardsfolder/p/parallax_wave.txt b/forge-gui/res/cardsfolder/p/parallax_wave.txt index eb087bdc4b1..afe19bab11e 100644 --- a/forge-gui/res/cardsfolder/p/parallax_wave.txt +++ b/forge-gui/res/cardsfolder/p/parallax_wave.txt @@ -2,10 +2,10 @@ Name:Parallax Wave ManaCost:2 W W Types:Enchantment K:Fading:5 -A:AB$ ChangeZone | Cost$ SubCounter<1/FADE> | ValidTgts$ Creature | TgtPrompt$ Select target creature | Origin$ Battlefield | Destination$ Exile | Imprint$ True | SpellDescription$ Exile target creature. +A:AB$ ChangeZone | Cost$ SubCounter<1/FADE> | ValidTgts$ Creature | TgtPrompt$ Select target creature | Origin$ Battlefield | Destination$ Exile | RememberTargets$ True | SpellDescription$ Exile target creature. T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME leaves the battlefield, each player returns to the battlefield all cards they own exiled with CARDNAME. -SVar:TrigReturn:DB$ ChangeZone | Defined$ Imprinted | Origin$ Exile | Destination$ Battlefield | SubAbility$ DBCleanup -SVar:DBCleanup:DB$ Cleanup | ClearImprinted$ True +SVar:TrigReturn:DB$ ChangeZoneAll | ChangeType$ Card.IsRemembered+ExiledWithSource | Origin$ Exile | Destination$ Battlefield | SubAbility$ DBCleanup +SVar:DBCleanup:DB$Cleanup | ClearRemembered$ True SVar:PlayMain1:TRUE AI:RemoveDeck:All SVar:Picture:http://www.wizards.com/global/images/magic/general/parallax_wave.jpg From 8e40a9dd23b9b1e0edeed241497a9d3d43b1fcf9 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Mon, 7 Dec 2020 16:38:15 -0500 Subject: [PATCH 28/97] migrate CMR and un stuff that was put in Upcoming --- .../res/cardsfolder/{upcoming => a}/abomination_of_llanowar.txt | 0 .../cardsfolder/{upcoming => a}/aesi_tyrant_of_gyre_strait.txt | 0 .../res/cardsfolder/{upcoming => a}/akroma_vision_of_ixidor.txt | 0 forge-gui/res/cardsfolder/{upcoming => a}/akromas_will.txt | 0 .../res/cardsfolder/{upcoming => a}/alena_kessig_trapper.txt | 0 .../res/cardsfolder/{upcoming => a}/alharu_solemn_ritualist.txt | 0 .../res/cardsfolder/{upcoming => a}/amareth_the_lustrous.txt | 0 forge-gui/res/cardsfolder/{upcoming => a}/amateur_auteur.txt | 0 forge-gui/res/cardsfolder/{upcoming => a}/amphin_mutineer.txt | 0 .../res/cardsfolder/{upcoming => a}/anara_wolvid_familiar.txt | 0 forge-gui/res/cardsfolder/{upcoming => a}/annoyed_altisaur.txt | 0 forge-gui/res/cardsfolder/{upcoming => a}/anointer_of_valor.txt | 0 forge-gui/res/cardsfolder/{upcoming => a}/apex_devastator.txt | 0 .../res/cardsfolder/{upcoming => a}/araumi_of_the_dead_tide.txt | 0 .../res/cardsfolder/{upcoming => a}/archelos_lagoon_mystic.txt | 0 .../res/cardsfolder/{upcoming => a}/archon_of_coronation.txt | 0 .../cardsfolder/{upcoming => a}/ardenn_intrepid_archaeologist.txt | 0 .../res/cardsfolder/{upcoming => a}/armix_filigree_thrasher.txt | 0 forge-gui/res/cardsfolder/{upcoming => a}/armored_skyhunter.txt | 0 forge-gui/res/cardsfolder/{upcoming => a}/aurora_phoenix.txt | 0 .../res/cardsfolder/{upcoming => a}/averna_the_chaos_bloom.txt | 0 forge-gui/res/cardsfolder/{upcoming => a}/azure_fleet_admiral.txt | 0 forge-gui/res/cardsfolder/{upcoming => b}/beast_in_show.txt | 0 .../res/cardsfolder/{upcoming => b}/belbe_corrupted_observer.txt | 0 .../cardsfolder/{upcoming => b}/bell_borca_spectral_sergeant.txt | 0 forge-gui/res/cardsfolder/{upcoming => b}/benevolent_blessing.txt | 0 forge-gui/res/cardsfolder/{upcoming => b}/biowaste_blob.txt | 0 .../res/cardsfolder/{upcoming => b}/bladegriff_prototype.txt | 0 forge-gui/res/cardsfolder/{upcoming => b}/blast_from_the_past.txt | 0 forge-gui/res/cardsfolder/{upcoming => b}/blazing_sunsteel.txt | 0 forge-gui/res/cardsfolder/{upcoming => b}/blim_comedic_genius.txt | 0 forge-gui/res/cardsfolder/{upcoming => b}/boarding_party.txt | 0 forge-gui/res/cardsfolder/{upcoming => b}/body_of_knowledge.txt | 0 .../res/cardsfolder/{upcoming => b}/breeches_brazen_plunderer.txt | 0 forge-gui/res/cardsfolder/{upcoming => b}/briarblade_adept.txt | 0 .../res/cardsfolder/{upcoming => b}/brinelin_the_moon_kraken.txt | 0 .../res/cardsfolder/{upcoming => c}/captain_vargus_wrath.txt | 0 forge-gui/res/cardsfolder/{upcoming => c}/clambassadors.txt | 0 forge-gui/res/cardsfolder/{upcoming => c}/coastline_marauders.txt | 0 forge-gui/res/cardsfolder/{upcoming => c}/coercive_recruiter.txt | 0 .../res/cardsfolder/{upcoming => c}/colfenor_the_last_yew.txt | 0 forge-gui/res/cardsfolder/{upcoming => c}/commanders_plate.txt | 0 forge-gui/res/cardsfolder/{upcoming => c}/court_of_ambition.txt | 0 forge-gui/res/cardsfolder/{upcoming => c}/court_of_bounty.txt | 0 forge-gui/res/cardsfolder/{upcoming => c}/court_of_cunning.txt | 0 forge-gui/res/cardsfolder/{upcoming => c}/court_of_grace.txt | 0 forge-gui/res/cardsfolder/{upcoming => c}/court_of_ire.txt | 0 .../res/cardsfolder/{upcoming => c}/crimson_fleet_commodore.txt | 0 forge-gui/res/cardsfolder/{upcoming => c}/crow_storm.txt | 0 forge-gui/res/cardsfolder/{upcoming => c}/curious_killbot.txt | 0 .../res/cardsfolder/{upcoming => d}/dargo_the_shipwrecker.txt | 0 forge-gui/res/cardsfolder/{upcoming => d}/dawnblade_regent.txt | 0 forge-gui/res/cardsfolder/{upcoming => d}/delighted_killbot.txt | 0 forge-gui/res/cardsfolder/{upcoming => d}/demonic_lore.txt | 0 forge-gui/res/cardsfolder/{upcoming => d}/despondent_killbot.txt | 0 forge-gui/res/cardsfolder/{upcoming => d}/distract.txt | 0 forge-gui/res/cardsfolder/{upcoming => d}/drake_stone.txt | 0 forge-gui/res/cardsfolder/{upcoming => e}/earl_of_squirrel.txt | 0 .../res/cardsfolder/{upcoming => e}/eligeth_crossroads_augur.txt | 0 forge-gui/res/cardsfolder/{upcoming => e}/elvish_doomsayer.txt | 0 forge-gui/res/cardsfolder/{upcoming => e}/elvish_dreadlord.txt | 0 forge-gui/res/cardsfolder/{upcoming => e}/emberwilde_captain.txt | 0 forge-gui/res/cardsfolder/{upcoming => e}/enraged_killbot.txt | 0 forge-gui/res/cardsfolder/{upcoming => e}/enthrall.txt | 0 .../res/cardsfolder/{upcoming => e}/esior_wardwing_familiar.txt | 0 forge-gui/res/cardsfolder/{upcoming => e}/explosion_of_riches.txt | 0 .../res/cardsfolder/{upcoming => e}/exquisite_huntmaster.txt | 0 forge-gui/res/cardsfolder/{upcoming => e}/eyeblight_cullers.txt | 0 forge-gui/res/cardsfolder/{upcoming => f}/fall_from_favor.txt | 0 .../cardsfolder/{upcoming => f}/falthis_shadowcat_familiar.txt | 0 .../res/cardsfolder/{upcoming => f}/fathom_fleet_swordjack.txt | 0 forge-gui/res/cardsfolder/{upcoming => f}/feast_of_succession.txt | 0 forge-gui/res/cardsfolder/{upcoming => f}/fin_clade_fugitives.txt | 0 forge-gui/res/cardsfolder/{upcoming => f}/flamekin_herald.txt | 0 forge-gui/res/cardsfolder/{upcoming => f}/forceful_denial.txt | 0 .../res/cardsfolder/{upcoming => f}/form_of_the_squirrel.txt | 0 .../res/cardsfolder/{upcoming => f}/frenzied_saddlebrute.txt | 0 forge-gui/res/cardsfolder/{upcoming => g}/ghen_arcanum_weaver.txt | 0 .../res/cardsfolder/{upcoming => g}/ghost_of_ramirez_depietro.txt | 0 .../cardsfolder/{upcoming => g}/gilanra_caller_of_wirewood.txt | 0 .../cardsfolder/{upcoming => g}/glacian_powerstone_engineer.txt | 0 .../cardsfolder/{upcoming => g}/gnostro_voice_of_the_crags.txt | 0 .../res/cardsfolder/{upcoming => g}/gor_muldrak_amphinologist.txt | 0 forge-gui/res/cardsfolder/{upcoming => g}/guildless_commons.txt | 0 .../res/cardsfolder/{upcoming => h}/halana_kessig_ranger.txt | 0 .../res/cardsfolder/{upcoming => h}/hamza_guardian_of_arashin.txt | 0 forge-gui/res/cardsfolder/{upcoming => h}/hans_eriksson.txt | 0 forge-gui/res/cardsfolder/{upcoming => h}/hellkite_courser.txt | 0 forge-gui/res/cardsfolder/{upcoming => h}/horizon_stone.txt | 0 forge-gui/res/cardsfolder/{upcoming => h}/hullbreacher.txt | 0 .../res/cardsfolder/{upcoming => i}/ich_tekik_salvage_splicer.txt | 0 .../res/cardsfolder/{upcoming => i}/imoti_celebrant_of_bounty.txt | 0 forge-gui/res/cardsfolder/{upcoming => i}/impulsive_pilferer.txt | 0 forge-gui/res/cardsfolder/{upcoming => i}/ingenuity_engine.txt | 0 forge-gui/res/cardsfolder/{upcoming => j}/jackknight.txt | 0 .../cardsfolder/{upcoming => j}/jared_carthalion_true_heir.txt | 0 forge-gui/res/cardsfolder/{upcoming => j}/jeska_thrice_reborn.txt | 0 forge-gui/res/cardsfolder/{upcoming => j}/jeskas_will.txt | 0 forge-gui/res/cardsfolder/{upcoming => j}/jeweled_lotus.txt | 0 .../res/cardsfolder/{upcoming => j}/juri_master_of_the_revue.txt | 0 .../res/cardsfolder/{upcoming => k}/kamahl_heart_of_krosa.txt | 0 forge-gui/res/cardsfolder/{upcoming => k}/kamahls_will.txt | 0 forge-gui/res/cardsfolder/{upcoming => k}/kangee_sky_warden.txt | 0 forge-gui/res/cardsfolder/{upcoming => k}/kangees_lieutenant.txt | 0 .../res/cardsfolder/{upcoming => k}/kediss_emberclaw_familiar.txt | 0 .../res/cardsfolder/{upcoming => k}/keeper_of_the_accord.txt | 0 .../res/cardsfolder/{upcoming => k}/keleth_sunmane_familiar.txt | 0 .../res/cardsfolder/{upcoming => k}/keskit_the_flesh_sculptor.txt | 0 forge-gui/res/cardsfolder/{upcoming => k}/kinsbaile_courier.txt | 0 forge-gui/res/cardsfolder/{upcoming => k}/kitesail_skirmisher.txt | 0 .../res/cardsfolder/{upcoming => k}/kodama_of_the_east_tree.txt | 0 forge-gui/res/cardsfolder/{upcoming => k}/krark_the_thumbless.txt | 0 .../res/cardsfolder/{upcoming => k}/kwain_itinerant_meddler.txt | 0 forge-gui/res/cardsfolder/{upcoming => l}/laboratory_drudge.txt | 0 .../cardsfolder/{upcoming => l}/lathiel_the_bounteous_dawn.txt | 0 .../res/cardsfolder/{upcoming => l}/liesa_shroud_of_dusk.txt | 0 .../res/cardsfolder/{upcoming => l}/livio_oathsworn_sentinel.txt | 0 forge-gui/res/cardsfolder/{upcoming => m}/maelstrom_colossus.txt | 0 forge-gui/res/cardsfolder/{upcoming => m}/magus_of_the_order.txt | 0 .../cardsfolder/{upcoming => m}/malcolm_keen-eyed_navigator.txt | 0 forge-gui/res/cardsfolder/{upcoming => m}/merchant_raiders.txt | 0 forge-gui/res/cardsfolder/{upcoming => m}/meteoric_mace.txt | 0 .../res/cardsfolder/{upcoming => m}/miara_thorn_of_the_glade.txt | 0 forge-gui/res/cardsfolder/{upcoming => m}/mnemonic_deluge.txt | 0 .../cardsfolder/{upcoming => n}/nadier_agent_of_the_duskenel.txt | 0 forge-gui/res/cardsfolder/{upcoming => n}/nadiers_nightblade.txt | 0 forge-gui/res/cardsfolder/{upcoming => n}/natural_reclamation.txt | 0 forge-gui/res/cardsfolder/{upcoming => n}/necrotic_hex.txt | 0 .../res/cardsfolder/{upcoming => n}/nevinyrral_urborg_tyrant.txt | 0 .../res/cardsfolder/{upcoming => n}/nightshade_harvester.txt | 0 forge-gui/res/cardsfolder/{upcoming => n}/novellamental.txt | 0 .../res/cardsfolder/{upcoming => n}/numa_joraga_chieftain.txt | 0 .../res/cardsfolder/{upcoming => n}/nymris_oonas_trickster.txt | 0 .../res/cardsfolder/{upcoming => o}/obeka_brute_chronologist.txt | 0 forge-gui/res/cardsfolder/{upcoming => o}/old_fogey.txt | 0 forge-gui/res/cardsfolder/{upcoming => o}/opposition_agent.txt | 0 forge-gui/res/cardsfolder/{upcoming => p}/phyrexian_triniform.txt | 0 forge-gui/res/cardsfolder/{upcoming => p}/plague_reaver.txt | 0 forge-gui/res/cardsfolder/{upcoming => p}/port_razer.txt | 0 .../res/cardsfolder/{upcoming => p}/prava_of_the_steel_legion.txt | 0 .../res/cardsfolder/{upcoming => p}/pride_of_the_perfect.txt | 0 forge-gui/res/cardsfolder/{upcoming => p}/profane_transfusion.txt | 0 forge-gui/res/cardsfolder/{upcoming => p}/promise_of_tomorrow.txt | 0 .../res/cardsfolder/{upcoming => r}/radiant_serra_archangel.txt | 0 forge-gui/res/cardsfolder/{upcoming => r}/rakshasa_debaser.txt | 0 .../cardsfolder/{upcoming => r}/rebbec_architect_of_ascension.txt | 0 .../res/cardsfolder/{upcoming => r}/rejuvenating_springs.txt | 0 forge-gui/res/cardsfolder/{upcoming => r}/reshape_the_earth.txt | 0 forge-gui/res/cardsfolder/{upcoming => r}/reyav_master_smith.txt | 0 .../res/cardsfolder/{upcoming => r}/rograkh_son_of_rohgahh.txt | 0 forge-gui/res/cardsfolder/{upcoming => r}/rootweaver_druid.txt | 0 .../cardsfolder/{upcoming => s}/sakashima_of_a_thousand_faces.txt | 0 forge-gui/res/cardsfolder/{upcoming => s}/sakashimas_protege.txt | 0 forge-gui/res/cardsfolder/{upcoming => s}/sakashimas_will.txt | 0 .../res/cardsfolder/{upcoming => s}/sengir_the_dark_baron.txt | 0 forge-gui/res/cardsfolder/{upcoming => s}/seraphic_greatsword.txt | 0 .../res/cardsfolder/{upcoming => s}/siani_eye_of_the_storm.txt | 0 forge-gui/res/cardsfolder/{upcoming => s}/slash_the_ranks.txt | 0 .../res/cardsfolder/{upcoming => s}/slurrk_all_ingesting.txt | 0 forge-gui/res/cardsfolder/{upcoming => s}/soul_of_eternity.txt | 0 forge-gui/res/cardsfolder/{upcoming => s}/soulfire_eruption.txt | 0 forge-gui/res/cardsfolder/{upcoming => s}/spectator_seating.txt | 0 .../res/cardsfolder/{upcoming => s}/sphinx_of_the_second_sun.txt | 0 forge-gui/res/cardsfolder/{upcoming => s}/staunch_throneguard.txt | 0 forge-gui/res/cardsfolder/{upcoming => s}/stumpsquall_hydra.txt | 0 forge-gui/res/cardsfolder/{upcoming => s}/sweet_gum_recluse.txt | 0 forge-gui/res/cardsfolder/{upcoming => s}/szats_will.txt | 0 forge-gui/res/cardsfolder/{upcoming => t}/target_minotaur.txt | 0 .../res/cardsfolder/{upcoming => t}/tevesh_szat_doom_of_fools.txt | 0 .../res/cardsfolder/{upcoming => t}/thalisse_reverent_medium.txt | 0 forge-gui/res/cardsfolder/{upcoming => t}/the_prismatic_piper.txt | 0 forge-gui/res/cardsfolder/{upcoming => t}/timely_ward.txt | 0 .../res/cardsfolder/{upcoming => t}/toggo_goblin_weaponsmith.txt | 0 .../res/cardsfolder/{upcoming => t}/tormod_the_desecrator.txt | 0 forge-gui/res/cardsfolder/{upcoming => t}/training_center.txt | 0 forge-gui/res/cardsfolder/{upcoming => t}/trench_behemoth.txt | 0 .../res/cardsfolder/{upcoming => t}/triumphant_reckoning.txt | 0 forge-gui/res/cardsfolder/{upcoming => t}/trove_tracker.txt | 0 forge-gui/res/cardsfolder/{upcoming => t}/tuya_bearclaw.txt | 0 forge-gui/res/cardsfolder/{upcoming => u}/undergrowth_stadium.txt | 0 forge-gui/res/cardsfolder/{upcoming => v}/vault_of_champions.txt | 0 forge-gui/res/cardsfolder/{upcoming => v}/volcanic_torrent.txt | 0 forge-gui/res/cardsfolder/{upcoming => w}/war_room.txt | 0 forge-gui/res/cardsfolder/{upcoming => w}/wheel_of_misfortune.txt | 0 forge-gui/res/cardsfolder/{upcoming => w}/wrong_turn.txt | 0 .../res/cardsfolder/{upcoming => w}/wyleth_soul_of_steel.txt | 0 .../res/cardsfolder/{upcoming => y}/yurlok_of_scorch_thrash.txt | 0 .../res/cardsfolder/{upcoming => z}/zara_renegade_recruiter.txt | 0 188 files changed, 0 insertions(+), 0 deletions(-) rename forge-gui/res/cardsfolder/{upcoming => a}/abomination_of_llanowar.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/aesi_tyrant_of_gyre_strait.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/akroma_vision_of_ixidor.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/akromas_will.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/alena_kessig_trapper.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/alharu_solemn_ritualist.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/amareth_the_lustrous.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/amateur_auteur.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/amphin_mutineer.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/anara_wolvid_familiar.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/annoyed_altisaur.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/anointer_of_valor.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/apex_devastator.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/araumi_of_the_dead_tide.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/archelos_lagoon_mystic.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/archon_of_coronation.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/ardenn_intrepid_archaeologist.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/armix_filigree_thrasher.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/armored_skyhunter.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/aurora_phoenix.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/averna_the_chaos_bloom.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => a}/azure_fleet_admiral.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => b}/beast_in_show.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => b}/belbe_corrupted_observer.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => b}/bell_borca_spectral_sergeant.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => b}/benevolent_blessing.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => b}/biowaste_blob.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => b}/bladegriff_prototype.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => b}/blast_from_the_past.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => b}/blazing_sunsteel.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => b}/blim_comedic_genius.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => b}/boarding_party.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => b}/body_of_knowledge.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => b}/breeches_brazen_plunderer.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => b}/briarblade_adept.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => b}/brinelin_the_moon_kraken.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => c}/captain_vargus_wrath.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => c}/clambassadors.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => c}/coastline_marauders.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => c}/coercive_recruiter.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => c}/colfenor_the_last_yew.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => c}/commanders_plate.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => c}/court_of_ambition.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => c}/court_of_bounty.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => c}/court_of_cunning.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => c}/court_of_grace.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => c}/court_of_ire.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => c}/crimson_fleet_commodore.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => c}/crow_storm.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => c}/curious_killbot.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => d}/dargo_the_shipwrecker.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => d}/dawnblade_regent.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => d}/delighted_killbot.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => d}/demonic_lore.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => d}/despondent_killbot.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => d}/distract.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => d}/drake_stone.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => e}/earl_of_squirrel.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => e}/eligeth_crossroads_augur.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => e}/elvish_doomsayer.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => e}/elvish_dreadlord.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => e}/emberwilde_captain.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => e}/enraged_killbot.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => e}/enthrall.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => e}/esior_wardwing_familiar.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => e}/explosion_of_riches.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => e}/exquisite_huntmaster.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => e}/eyeblight_cullers.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => f}/fall_from_favor.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => f}/falthis_shadowcat_familiar.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => f}/fathom_fleet_swordjack.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => f}/feast_of_succession.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => f}/fin_clade_fugitives.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => f}/flamekin_herald.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => f}/forceful_denial.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => f}/form_of_the_squirrel.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => f}/frenzied_saddlebrute.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => g}/ghen_arcanum_weaver.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => g}/ghost_of_ramirez_depietro.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => g}/gilanra_caller_of_wirewood.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => g}/glacian_powerstone_engineer.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => g}/gnostro_voice_of_the_crags.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => g}/gor_muldrak_amphinologist.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => g}/guildless_commons.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => h}/halana_kessig_ranger.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => h}/hamza_guardian_of_arashin.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => h}/hans_eriksson.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => h}/hellkite_courser.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => h}/horizon_stone.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => h}/hullbreacher.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => i}/ich_tekik_salvage_splicer.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => i}/imoti_celebrant_of_bounty.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => i}/impulsive_pilferer.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => i}/ingenuity_engine.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => j}/jackknight.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => j}/jared_carthalion_true_heir.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => j}/jeska_thrice_reborn.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => j}/jeskas_will.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => j}/jeweled_lotus.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => j}/juri_master_of_the_revue.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => k}/kamahl_heart_of_krosa.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => k}/kamahls_will.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => k}/kangee_sky_warden.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => k}/kangees_lieutenant.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => k}/kediss_emberclaw_familiar.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => k}/keeper_of_the_accord.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => k}/keleth_sunmane_familiar.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => k}/keskit_the_flesh_sculptor.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => k}/kinsbaile_courier.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => k}/kitesail_skirmisher.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => k}/kodama_of_the_east_tree.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => k}/krark_the_thumbless.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => k}/kwain_itinerant_meddler.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => l}/laboratory_drudge.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => l}/lathiel_the_bounteous_dawn.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => l}/liesa_shroud_of_dusk.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => l}/livio_oathsworn_sentinel.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => m}/maelstrom_colossus.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => m}/magus_of_the_order.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => m}/malcolm_keen-eyed_navigator.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => m}/merchant_raiders.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => m}/meteoric_mace.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => m}/miara_thorn_of_the_glade.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => m}/mnemonic_deluge.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => n}/nadier_agent_of_the_duskenel.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => n}/nadiers_nightblade.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => n}/natural_reclamation.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => n}/necrotic_hex.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => n}/nevinyrral_urborg_tyrant.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => n}/nightshade_harvester.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => n}/novellamental.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => n}/numa_joraga_chieftain.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => n}/nymris_oonas_trickster.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => o}/obeka_brute_chronologist.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => o}/old_fogey.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => o}/opposition_agent.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => p}/phyrexian_triniform.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => p}/plague_reaver.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => p}/port_razer.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => p}/prava_of_the_steel_legion.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => p}/pride_of_the_perfect.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => p}/profane_transfusion.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => p}/promise_of_tomorrow.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => r}/radiant_serra_archangel.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => r}/rakshasa_debaser.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => r}/rebbec_architect_of_ascension.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => r}/rejuvenating_springs.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => r}/reshape_the_earth.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => r}/reyav_master_smith.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => r}/rograkh_son_of_rohgahh.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => r}/rootweaver_druid.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => s}/sakashima_of_a_thousand_faces.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => s}/sakashimas_protege.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => s}/sakashimas_will.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => s}/sengir_the_dark_baron.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => s}/seraphic_greatsword.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => s}/siani_eye_of_the_storm.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => s}/slash_the_ranks.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => s}/slurrk_all_ingesting.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => s}/soul_of_eternity.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => s}/soulfire_eruption.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => s}/spectator_seating.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => s}/sphinx_of_the_second_sun.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => s}/staunch_throneguard.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => s}/stumpsquall_hydra.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => s}/sweet_gum_recluse.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => s}/szats_will.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => t}/target_minotaur.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => t}/tevesh_szat_doom_of_fools.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => t}/thalisse_reverent_medium.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => t}/the_prismatic_piper.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => t}/timely_ward.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => t}/toggo_goblin_weaponsmith.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => t}/tormod_the_desecrator.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => t}/training_center.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => t}/trench_behemoth.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => t}/triumphant_reckoning.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => t}/trove_tracker.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => t}/tuya_bearclaw.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => u}/undergrowth_stadium.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => v}/vault_of_champions.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => v}/volcanic_torrent.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => w}/war_room.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => w}/wheel_of_misfortune.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => w}/wrong_turn.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => w}/wyleth_soul_of_steel.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => y}/yurlok_of_scorch_thrash.txt (100%) rename forge-gui/res/cardsfolder/{upcoming => z}/zara_renegade_recruiter.txt (100%) diff --git a/forge-gui/res/cardsfolder/upcoming/abomination_of_llanowar.txt b/forge-gui/res/cardsfolder/a/abomination_of_llanowar.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/abomination_of_llanowar.txt rename to forge-gui/res/cardsfolder/a/abomination_of_llanowar.txt diff --git a/forge-gui/res/cardsfolder/upcoming/aesi_tyrant_of_gyre_strait.txt b/forge-gui/res/cardsfolder/a/aesi_tyrant_of_gyre_strait.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/aesi_tyrant_of_gyre_strait.txt rename to forge-gui/res/cardsfolder/a/aesi_tyrant_of_gyre_strait.txt diff --git a/forge-gui/res/cardsfolder/upcoming/akroma_vision_of_ixidor.txt b/forge-gui/res/cardsfolder/a/akroma_vision_of_ixidor.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/akroma_vision_of_ixidor.txt rename to forge-gui/res/cardsfolder/a/akroma_vision_of_ixidor.txt diff --git a/forge-gui/res/cardsfolder/upcoming/akromas_will.txt b/forge-gui/res/cardsfolder/a/akromas_will.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/akromas_will.txt rename to forge-gui/res/cardsfolder/a/akromas_will.txt diff --git a/forge-gui/res/cardsfolder/upcoming/alena_kessig_trapper.txt b/forge-gui/res/cardsfolder/a/alena_kessig_trapper.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/alena_kessig_trapper.txt rename to forge-gui/res/cardsfolder/a/alena_kessig_trapper.txt diff --git a/forge-gui/res/cardsfolder/upcoming/alharu_solemn_ritualist.txt b/forge-gui/res/cardsfolder/a/alharu_solemn_ritualist.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/alharu_solemn_ritualist.txt rename to forge-gui/res/cardsfolder/a/alharu_solemn_ritualist.txt diff --git a/forge-gui/res/cardsfolder/upcoming/amareth_the_lustrous.txt b/forge-gui/res/cardsfolder/a/amareth_the_lustrous.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/amareth_the_lustrous.txt rename to forge-gui/res/cardsfolder/a/amareth_the_lustrous.txt diff --git a/forge-gui/res/cardsfolder/upcoming/amateur_auteur.txt b/forge-gui/res/cardsfolder/a/amateur_auteur.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/amateur_auteur.txt rename to forge-gui/res/cardsfolder/a/amateur_auteur.txt diff --git a/forge-gui/res/cardsfolder/upcoming/amphin_mutineer.txt b/forge-gui/res/cardsfolder/a/amphin_mutineer.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/amphin_mutineer.txt rename to forge-gui/res/cardsfolder/a/amphin_mutineer.txt diff --git a/forge-gui/res/cardsfolder/upcoming/anara_wolvid_familiar.txt b/forge-gui/res/cardsfolder/a/anara_wolvid_familiar.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/anara_wolvid_familiar.txt rename to forge-gui/res/cardsfolder/a/anara_wolvid_familiar.txt diff --git a/forge-gui/res/cardsfolder/upcoming/annoyed_altisaur.txt b/forge-gui/res/cardsfolder/a/annoyed_altisaur.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/annoyed_altisaur.txt rename to forge-gui/res/cardsfolder/a/annoyed_altisaur.txt diff --git a/forge-gui/res/cardsfolder/upcoming/anointer_of_valor.txt b/forge-gui/res/cardsfolder/a/anointer_of_valor.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/anointer_of_valor.txt rename to forge-gui/res/cardsfolder/a/anointer_of_valor.txt diff --git a/forge-gui/res/cardsfolder/upcoming/apex_devastator.txt b/forge-gui/res/cardsfolder/a/apex_devastator.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/apex_devastator.txt rename to forge-gui/res/cardsfolder/a/apex_devastator.txt diff --git a/forge-gui/res/cardsfolder/upcoming/araumi_of_the_dead_tide.txt b/forge-gui/res/cardsfolder/a/araumi_of_the_dead_tide.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/araumi_of_the_dead_tide.txt rename to forge-gui/res/cardsfolder/a/araumi_of_the_dead_tide.txt diff --git a/forge-gui/res/cardsfolder/upcoming/archelos_lagoon_mystic.txt b/forge-gui/res/cardsfolder/a/archelos_lagoon_mystic.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/archelos_lagoon_mystic.txt rename to forge-gui/res/cardsfolder/a/archelos_lagoon_mystic.txt diff --git a/forge-gui/res/cardsfolder/upcoming/archon_of_coronation.txt b/forge-gui/res/cardsfolder/a/archon_of_coronation.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/archon_of_coronation.txt rename to forge-gui/res/cardsfolder/a/archon_of_coronation.txt diff --git a/forge-gui/res/cardsfolder/upcoming/ardenn_intrepid_archaeologist.txt b/forge-gui/res/cardsfolder/a/ardenn_intrepid_archaeologist.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/ardenn_intrepid_archaeologist.txt rename to forge-gui/res/cardsfolder/a/ardenn_intrepid_archaeologist.txt diff --git a/forge-gui/res/cardsfolder/upcoming/armix_filigree_thrasher.txt b/forge-gui/res/cardsfolder/a/armix_filigree_thrasher.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/armix_filigree_thrasher.txt rename to forge-gui/res/cardsfolder/a/armix_filigree_thrasher.txt diff --git a/forge-gui/res/cardsfolder/upcoming/armored_skyhunter.txt b/forge-gui/res/cardsfolder/a/armored_skyhunter.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/armored_skyhunter.txt rename to forge-gui/res/cardsfolder/a/armored_skyhunter.txt diff --git a/forge-gui/res/cardsfolder/upcoming/aurora_phoenix.txt b/forge-gui/res/cardsfolder/a/aurora_phoenix.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/aurora_phoenix.txt rename to forge-gui/res/cardsfolder/a/aurora_phoenix.txt diff --git a/forge-gui/res/cardsfolder/upcoming/averna_the_chaos_bloom.txt b/forge-gui/res/cardsfolder/a/averna_the_chaos_bloom.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/averna_the_chaos_bloom.txt rename to forge-gui/res/cardsfolder/a/averna_the_chaos_bloom.txt diff --git a/forge-gui/res/cardsfolder/upcoming/azure_fleet_admiral.txt b/forge-gui/res/cardsfolder/a/azure_fleet_admiral.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/azure_fleet_admiral.txt rename to forge-gui/res/cardsfolder/a/azure_fleet_admiral.txt diff --git a/forge-gui/res/cardsfolder/upcoming/beast_in_show.txt b/forge-gui/res/cardsfolder/b/beast_in_show.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/beast_in_show.txt rename to forge-gui/res/cardsfolder/b/beast_in_show.txt diff --git a/forge-gui/res/cardsfolder/upcoming/belbe_corrupted_observer.txt b/forge-gui/res/cardsfolder/b/belbe_corrupted_observer.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/belbe_corrupted_observer.txt rename to forge-gui/res/cardsfolder/b/belbe_corrupted_observer.txt diff --git a/forge-gui/res/cardsfolder/upcoming/bell_borca_spectral_sergeant.txt b/forge-gui/res/cardsfolder/b/bell_borca_spectral_sergeant.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/bell_borca_spectral_sergeant.txt rename to forge-gui/res/cardsfolder/b/bell_borca_spectral_sergeant.txt diff --git a/forge-gui/res/cardsfolder/upcoming/benevolent_blessing.txt b/forge-gui/res/cardsfolder/b/benevolent_blessing.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/benevolent_blessing.txt rename to forge-gui/res/cardsfolder/b/benevolent_blessing.txt diff --git a/forge-gui/res/cardsfolder/upcoming/biowaste_blob.txt b/forge-gui/res/cardsfolder/b/biowaste_blob.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/biowaste_blob.txt rename to forge-gui/res/cardsfolder/b/biowaste_blob.txt diff --git a/forge-gui/res/cardsfolder/upcoming/bladegriff_prototype.txt b/forge-gui/res/cardsfolder/b/bladegriff_prototype.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/bladegriff_prototype.txt rename to forge-gui/res/cardsfolder/b/bladegriff_prototype.txt diff --git a/forge-gui/res/cardsfolder/upcoming/blast_from_the_past.txt b/forge-gui/res/cardsfolder/b/blast_from_the_past.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/blast_from_the_past.txt rename to forge-gui/res/cardsfolder/b/blast_from_the_past.txt diff --git a/forge-gui/res/cardsfolder/upcoming/blazing_sunsteel.txt b/forge-gui/res/cardsfolder/b/blazing_sunsteel.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/blazing_sunsteel.txt rename to forge-gui/res/cardsfolder/b/blazing_sunsteel.txt diff --git a/forge-gui/res/cardsfolder/upcoming/blim_comedic_genius.txt b/forge-gui/res/cardsfolder/b/blim_comedic_genius.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/blim_comedic_genius.txt rename to forge-gui/res/cardsfolder/b/blim_comedic_genius.txt diff --git a/forge-gui/res/cardsfolder/upcoming/boarding_party.txt b/forge-gui/res/cardsfolder/b/boarding_party.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/boarding_party.txt rename to forge-gui/res/cardsfolder/b/boarding_party.txt diff --git a/forge-gui/res/cardsfolder/upcoming/body_of_knowledge.txt b/forge-gui/res/cardsfolder/b/body_of_knowledge.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/body_of_knowledge.txt rename to forge-gui/res/cardsfolder/b/body_of_knowledge.txt diff --git a/forge-gui/res/cardsfolder/upcoming/breeches_brazen_plunderer.txt b/forge-gui/res/cardsfolder/b/breeches_brazen_plunderer.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/breeches_brazen_plunderer.txt rename to forge-gui/res/cardsfolder/b/breeches_brazen_plunderer.txt diff --git a/forge-gui/res/cardsfolder/upcoming/briarblade_adept.txt b/forge-gui/res/cardsfolder/b/briarblade_adept.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/briarblade_adept.txt rename to forge-gui/res/cardsfolder/b/briarblade_adept.txt diff --git a/forge-gui/res/cardsfolder/upcoming/brinelin_the_moon_kraken.txt b/forge-gui/res/cardsfolder/b/brinelin_the_moon_kraken.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/brinelin_the_moon_kraken.txt rename to forge-gui/res/cardsfolder/b/brinelin_the_moon_kraken.txt diff --git a/forge-gui/res/cardsfolder/upcoming/captain_vargus_wrath.txt b/forge-gui/res/cardsfolder/c/captain_vargus_wrath.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/captain_vargus_wrath.txt rename to forge-gui/res/cardsfolder/c/captain_vargus_wrath.txt diff --git a/forge-gui/res/cardsfolder/upcoming/clambassadors.txt b/forge-gui/res/cardsfolder/c/clambassadors.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/clambassadors.txt rename to forge-gui/res/cardsfolder/c/clambassadors.txt diff --git a/forge-gui/res/cardsfolder/upcoming/coastline_marauders.txt b/forge-gui/res/cardsfolder/c/coastline_marauders.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/coastline_marauders.txt rename to forge-gui/res/cardsfolder/c/coastline_marauders.txt diff --git a/forge-gui/res/cardsfolder/upcoming/coercive_recruiter.txt b/forge-gui/res/cardsfolder/c/coercive_recruiter.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/coercive_recruiter.txt rename to forge-gui/res/cardsfolder/c/coercive_recruiter.txt diff --git a/forge-gui/res/cardsfolder/upcoming/colfenor_the_last_yew.txt b/forge-gui/res/cardsfolder/c/colfenor_the_last_yew.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/colfenor_the_last_yew.txt rename to forge-gui/res/cardsfolder/c/colfenor_the_last_yew.txt diff --git a/forge-gui/res/cardsfolder/upcoming/commanders_plate.txt b/forge-gui/res/cardsfolder/c/commanders_plate.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/commanders_plate.txt rename to forge-gui/res/cardsfolder/c/commanders_plate.txt diff --git a/forge-gui/res/cardsfolder/upcoming/court_of_ambition.txt b/forge-gui/res/cardsfolder/c/court_of_ambition.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/court_of_ambition.txt rename to forge-gui/res/cardsfolder/c/court_of_ambition.txt diff --git a/forge-gui/res/cardsfolder/upcoming/court_of_bounty.txt b/forge-gui/res/cardsfolder/c/court_of_bounty.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/court_of_bounty.txt rename to forge-gui/res/cardsfolder/c/court_of_bounty.txt diff --git a/forge-gui/res/cardsfolder/upcoming/court_of_cunning.txt b/forge-gui/res/cardsfolder/c/court_of_cunning.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/court_of_cunning.txt rename to forge-gui/res/cardsfolder/c/court_of_cunning.txt diff --git a/forge-gui/res/cardsfolder/upcoming/court_of_grace.txt b/forge-gui/res/cardsfolder/c/court_of_grace.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/court_of_grace.txt rename to forge-gui/res/cardsfolder/c/court_of_grace.txt diff --git a/forge-gui/res/cardsfolder/upcoming/court_of_ire.txt b/forge-gui/res/cardsfolder/c/court_of_ire.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/court_of_ire.txt rename to forge-gui/res/cardsfolder/c/court_of_ire.txt diff --git a/forge-gui/res/cardsfolder/upcoming/crimson_fleet_commodore.txt b/forge-gui/res/cardsfolder/c/crimson_fleet_commodore.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/crimson_fleet_commodore.txt rename to forge-gui/res/cardsfolder/c/crimson_fleet_commodore.txt diff --git a/forge-gui/res/cardsfolder/upcoming/crow_storm.txt b/forge-gui/res/cardsfolder/c/crow_storm.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/crow_storm.txt rename to forge-gui/res/cardsfolder/c/crow_storm.txt diff --git a/forge-gui/res/cardsfolder/upcoming/curious_killbot.txt b/forge-gui/res/cardsfolder/c/curious_killbot.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/curious_killbot.txt rename to forge-gui/res/cardsfolder/c/curious_killbot.txt diff --git a/forge-gui/res/cardsfolder/upcoming/dargo_the_shipwrecker.txt b/forge-gui/res/cardsfolder/d/dargo_the_shipwrecker.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/dargo_the_shipwrecker.txt rename to forge-gui/res/cardsfolder/d/dargo_the_shipwrecker.txt diff --git a/forge-gui/res/cardsfolder/upcoming/dawnblade_regent.txt b/forge-gui/res/cardsfolder/d/dawnblade_regent.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/dawnblade_regent.txt rename to forge-gui/res/cardsfolder/d/dawnblade_regent.txt diff --git a/forge-gui/res/cardsfolder/upcoming/delighted_killbot.txt b/forge-gui/res/cardsfolder/d/delighted_killbot.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/delighted_killbot.txt rename to forge-gui/res/cardsfolder/d/delighted_killbot.txt diff --git a/forge-gui/res/cardsfolder/upcoming/demonic_lore.txt b/forge-gui/res/cardsfolder/d/demonic_lore.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/demonic_lore.txt rename to forge-gui/res/cardsfolder/d/demonic_lore.txt diff --git a/forge-gui/res/cardsfolder/upcoming/despondent_killbot.txt b/forge-gui/res/cardsfolder/d/despondent_killbot.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/despondent_killbot.txt rename to forge-gui/res/cardsfolder/d/despondent_killbot.txt diff --git a/forge-gui/res/cardsfolder/upcoming/distract.txt b/forge-gui/res/cardsfolder/d/distract.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/distract.txt rename to forge-gui/res/cardsfolder/d/distract.txt diff --git a/forge-gui/res/cardsfolder/upcoming/drake_stone.txt b/forge-gui/res/cardsfolder/d/drake_stone.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/drake_stone.txt rename to forge-gui/res/cardsfolder/d/drake_stone.txt diff --git a/forge-gui/res/cardsfolder/upcoming/earl_of_squirrel.txt b/forge-gui/res/cardsfolder/e/earl_of_squirrel.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/earl_of_squirrel.txt rename to forge-gui/res/cardsfolder/e/earl_of_squirrel.txt diff --git a/forge-gui/res/cardsfolder/upcoming/eligeth_crossroads_augur.txt b/forge-gui/res/cardsfolder/e/eligeth_crossroads_augur.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/eligeth_crossroads_augur.txt rename to forge-gui/res/cardsfolder/e/eligeth_crossroads_augur.txt diff --git a/forge-gui/res/cardsfolder/upcoming/elvish_doomsayer.txt b/forge-gui/res/cardsfolder/e/elvish_doomsayer.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/elvish_doomsayer.txt rename to forge-gui/res/cardsfolder/e/elvish_doomsayer.txt diff --git a/forge-gui/res/cardsfolder/upcoming/elvish_dreadlord.txt b/forge-gui/res/cardsfolder/e/elvish_dreadlord.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/elvish_dreadlord.txt rename to forge-gui/res/cardsfolder/e/elvish_dreadlord.txt diff --git a/forge-gui/res/cardsfolder/upcoming/emberwilde_captain.txt b/forge-gui/res/cardsfolder/e/emberwilde_captain.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/emberwilde_captain.txt rename to forge-gui/res/cardsfolder/e/emberwilde_captain.txt diff --git a/forge-gui/res/cardsfolder/upcoming/enraged_killbot.txt b/forge-gui/res/cardsfolder/e/enraged_killbot.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/enraged_killbot.txt rename to forge-gui/res/cardsfolder/e/enraged_killbot.txt diff --git a/forge-gui/res/cardsfolder/upcoming/enthrall.txt b/forge-gui/res/cardsfolder/e/enthrall.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/enthrall.txt rename to forge-gui/res/cardsfolder/e/enthrall.txt diff --git a/forge-gui/res/cardsfolder/upcoming/esior_wardwing_familiar.txt b/forge-gui/res/cardsfolder/e/esior_wardwing_familiar.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/esior_wardwing_familiar.txt rename to forge-gui/res/cardsfolder/e/esior_wardwing_familiar.txt diff --git a/forge-gui/res/cardsfolder/upcoming/explosion_of_riches.txt b/forge-gui/res/cardsfolder/e/explosion_of_riches.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/explosion_of_riches.txt rename to forge-gui/res/cardsfolder/e/explosion_of_riches.txt diff --git a/forge-gui/res/cardsfolder/upcoming/exquisite_huntmaster.txt b/forge-gui/res/cardsfolder/e/exquisite_huntmaster.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/exquisite_huntmaster.txt rename to forge-gui/res/cardsfolder/e/exquisite_huntmaster.txt diff --git a/forge-gui/res/cardsfolder/upcoming/eyeblight_cullers.txt b/forge-gui/res/cardsfolder/e/eyeblight_cullers.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/eyeblight_cullers.txt rename to forge-gui/res/cardsfolder/e/eyeblight_cullers.txt diff --git a/forge-gui/res/cardsfolder/upcoming/fall_from_favor.txt b/forge-gui/res/cardsfolder/f/fall_from_favor.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/fall_from_favor.txt rename to forge-gui/res/cardsfolder/f/fall_from_favor.txt diff --git a/forge-gui/res/cardsfolder/upcoming/falthis_shadowcat_familiar.txt b/forge-gui/res/cardsfolder/f/falthis_shadowcat_familiar.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/falthis_shadowcat_familiar.txt rename to forge-gui/res/cardsfolder/f/falthis_shadowcat_familiar.txt diff --git a/forge-gui/res/cardsfolder/upcoming/fathom_fleet_swordjack.txt b/forge-gui/res/cardsfolder/f/fathom_fleet_swordjack.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/fathom_fleet_swordjack.txt rename to forge-gui/res/cardsfolder/f/fathom_fleet_swordjack.txt diff --git a/forge-gui/res/cardsfolder/upcoming/feast_of_succession.txt b/forge-gui/res/cardsfolder/f/feast_of_succession.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/feast_of_succession.txt rename to forge-gui/res/cardsfolder/f/feast_of_succession.txt diff --git a/forge-gui/res/cardsfolder/upcoming/fin_clade_fugitives.txt b/forge-gui/res/cardsfolder/f/fin_clade_fugitives.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/fin_clade_fugitives.txt rename to forge-gui/res/cardsfolder/f/fin_clade_fugitives.txt diff --git a/forge-gui/res/cardsfolder/upcoming/flamekin_herald.txt b/forge-gui/res/cardsfolder/f/flamekin_herald.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/flamekin_herald.txt rename to forge-gui/res/cardsfolder/f/flamekin_herald.txt diff --git a/forge-gui/res/cardsfolder/upcoming/forceful_denial.txt b/forge-gui/res/cardsfolder/f/forceful_denial.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/forceful_denial.txt rename to forge-gui/res/cardsfolder/f/forceful_denial.txt diff --git a/forge-gui/res/cardsfolder/upcoming/form_of_the_squirrel.txt b/forge-gui/res/cardsfolder/f/form_of_the_squirrel.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/form_of_the_squirrel.txt rename to forge-gui/res/cardsfolder/f/form_of_the_squirrel.txt diff --git a/forge-gui/res/cardsfolder/upcoming/frenzied_saddlebrute.txt b/forge-gui/res/cardsfolder/f/frenzied_saddlebrute.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/frenzied_saddlebrute.txt rename to forge-gui/res/cardsfolder/f/frenzied_saddlebrute.txt diff --git a/forge-gui/res/cardsfolder/upcoming/ghen_arcanum_weaver.txt b/forge-gui/res/cardsfolder/g/ghen_arcanum_weaver.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/ghen_arcanum_weaver.txt rename to forge-gui/res/cardsfolder/g/ghen_arcanum_weaver.txt diff --git a/forge-gui/res/cardsfolder/upcoming/ghost_of_ramirez_depietro.txt b/forge-gui/res/cardsfolder/g/ghost_of_ramirez_depietro.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/ghost_of_ramirez_depietro.txt rename to forge-gui/res/cardsfolder/g/ghost_of_ramirez_depietro.txt diff --git a/forge-gui/res/cardsfolder/upcoming/gilanra_caller_of_wirewood.txt b/forge-gui/res/cardsfolder/g/gilanra_caller_of_wirewood.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/gilanra_caller_of_wirewood.txt rename to forge-gui/res/cardsfolder/g/gilanra_caller_of_wirewood.txt diff --git a/forge-gui/res/cardsfolder/upcoming/glacian_powerstone_engineer.txt b/forge-gui/res/cardsfolder/g/glacian_powerstone_engineer.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/glacian_powerstone_engineer.txt rename to forge-gui/res/cardsfolder/g/glacian_powerstone_engineer.txt diff --git a/forge-gui/res/cardsfolder/upcoming/gnostro_voice_of_the_crags.txt b/forge-gui/res/cardsfolder/g/gnostro_voice_of_the_crags.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/gnostro_voice_of_the_crags.txt rename to forge-gui/res/cardsfolder/g/gnostro_voice_of_the_crags.txt diff --git a/forge-gui/res/cardsfolder/upcoming/gor_muldrak_amphinologist.txt b/forge-gui/res/cardsfolder/g/gor_muldrak_amphinologist.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/gor_muldrak_amphinologist.txt rename to forge-gui/res/cardsfolder/g/gor_muldrak_amphinologist.txt diff --git a/forge-gui/res/cardsfolder/upcoming/guildless_commons.txt b/forge-gui/res/cardsfolder/g/guildless_commons.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/guildless_commons.txt rename to forge-gui/res/cardsfolder/g/guildless_commons.txt diff --git a/forge-gui/res/cardsfolder/upcoming/halana_kessig_ranger.txt b/forge-gui/res/cardsfolder/h/halana_kessig_ranger.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/halana_kessig_ranger.txt rename to forge-gui/res/cardsfolder/h/halana_kessig_ranger.txt diff --git a/forge-gui/res/cardsfolder/upcoming/hamza_guardian_of_arashin.txt b/forge-gui/res/cardsfolder/h/hamza_guardian_of_arashin.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/hamza_guardian_of_arashin.txt rename to forge-gui/res/cardsfolder/h/hamza_guardian_of_arashin.txt diff --git a/forge-gui/res/cardsfolder/upcoming/hans_eriksson.txt b/forge-gui/res/cardsfolder/h/hans_eriksson.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/hans_eriksson.txt rename to forge-gui/res/cardsfolder/h/hans_eriksson.txt diff --git a/forge-gui/res/cardsfolder/upcoming/hellkite_courser.txt b/forge-gui/res/cardsfolder/h/hellkite_courser.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/hellkite_courser.txt rename to forge-gui/res/cardsfolder/h/hellkite_courser.txt diff --git a/forge-gui/res/cardsfolder/upcoming/horizon_stone.txt b/forge-gui/res/cardsfolder/h/horizon_stone.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/horizon_stone.txt rename to forge-gui/res/cardsfolder/h/horizon_stone.txt diff --git a/forge-gui/res/cardsfolder/upcoming/hullbreacher.txt b/forge-gui/res/cardsfolder/h/hullbreacher.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/hullbreacher.txt rename to forge-gui/res/cardsfolder/h/hullbreacher.txt diff --git a/forge-gui/res/cardsfolder/upcoming/ich_tekik_salvage_splicer.txt b/forge-gui/res/cardsfolder/i/ich_tekik_salvage_splicer.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/ich_tekik_salvage_splicer.txt rename to forge-gui/res/cardsfolder/i/ich_tekik_salvage_splicer.txt diff --git a/forge-gui/res/cardsfolder/upcoming/imoti_celebrant_of_bounty.txt b/forge-gui/res/cardsfolder/i/imoti_celebrant_of_bounty.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/imoti_celebrant_of_bounty.txt rename to forge-gui/res/cardsfolder/i/imoti_celebrant_of_bounty.txt diff --git a/forge-gui/res/cardsfolder/upcoming/impulsive_pilferer.txt b/forge-gui/res/cardsfolder/i/impulsive_pilferer.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/impulsive_pilferer.txt rename to forge-gui/res/cardsfolder/i/impulsive_pilferer.txt diff --git a/forge-gui/res/cardsfolder/upcoming/ingenuity_engine.txt b/forge-gui/res/cardsfolder/i/ingenuity_engine.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/ingenuity_engine.txt rename to forge-gui/res/cardsfolder/i/ingenuity_engine.txt diff --git a/forge-gui/res/cardsfolder/upcoming/jackknight.txt b/forge-gui/res/cardsfolder/j/jackknight.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/jackknight.txt rename to forge-gui/res/cardsfolder/j/jackknight.txt diff --git a/forge-gui/res/cardsfolder/upcoming/jared_carthalion_true_heir.txt b/forge-gui/res/cardsfolder/j/jared_carthalion_true_heir.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/jared_carthalion_true_heir.txt rename to forge-gui/res/cardsfolder/j/jared_carthalion_true_heir.txt diff --git a/forge-gui/res/cardsfolder/upcoming/jeska_thrice_reborn.txt b/forge-gui/res/cardsfolder/j/jeska_thrice_reborn.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/jeska_thrice_reborn.txt rename to forge-gui/res/cardsfolder/j/jeska_thrice_reborn.txt diff --git a/forge-gui/res/cardsfolder/upcoming/jeskas_will.txt b/forge-gui/res/cardsfolder/j/jeskas_will.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/jeskas_will.txt rename to forge-gui/res/cardsfolder/j/jeskas_will.txt diff --git a/forge-gui/res/cardsfolder/upcoming/jeweled_lotus.txt b/forge-gui/res/cardsfolder/j/jeweled_lotus.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/jeweled_lotus.txt rename to forge-gui/res/cardsfolder/j/jeweled_lotus.txt diff --git a/forge-gui/res/cardsfolder/upcoming/juri_master_of_the_revue.txt b/forge-gui/res/cardsfolder/j/juri_master_of_the_revue.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/juri_master_of_the_revue.txt rename to forge-gui/res/cardsfolder/j/juri_master_of_the_revue.txt diff --git a/forge-gui/res/cardsfolder/upcoming/kamahl_heart_of_krosa.txt b/forge-gui/res/cardsfolder/k/kamahl_heart_of_krosa.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/kamahl_heart_of_krosa.txt rename to forge-gui/res/cardsfolder/k/kamahl_heart_of_krosa.txt diff --git a/forge-gui/res/cardsfolder/upcoming/kamahls_will.txt b/forge-gui/res/cardsfolder/k/kamahls_will.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/kamahls_will.txt rename to forge-gui/res/cardsfolder/k/kamahls_will.txt diff --git a/forge-gui/res/cardsfolder/upcoming/kangee_sky_warden.txt b/forge-gui/res/cardsfolder/k/kangee_sky_warden.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/kangee_sky_warden.txt rename to forge-gui/res/cardsfolder/k/kangee_sky_warden.txt diff --git a/forge-gui/res/cardsfolder/upcoming/kangees_lieutenant.txt b/forge-gui/res/cardsfolder/k/kangees_lieutenant.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/kangees_lieutenant.txt rename to forge-gui/res/cardsfolder/k/kangees_lieutenant.txt diff --git a/forge-gui/res/cardsfolder/upcoming/kediss_emberclaw_familiar.txt b/forge-gui/res/cardsfolder/k/kediss_emberclaw_familiar.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/kediss_emberclaw_familiar.txt rename to forge-gui/res/cardsfolder/k/kediss_emberclaw_familiar.txt diff --git a/forge-gui/res/cardsfolder/upcoming/keeper_of_the_accord.txt b/forge-gui/res/cardsfolder/k/keeper_of_the_accord.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/keeper_of_the_accord.txt rename to forge-gui/res/cardsfolder/k/keeper_of_the_accord.txt diff --git a/forge-gui/res/cardsfolder/upcoming/keleth_sunmane_familiar.txt b/forge-gui/res/cardsfolder/k/keleth_sunmane_familiar.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/keleth_sunmane_familiar.txt rename to forge-gui/res/cardsfolder/k/keleth_sunmane_familiar.txt diff --git a/forge-gui/res/cardsfolder/upcoming/keskit_the_flesh_sculptor.txt b/forge-gui/res/cardsfolder/k/keskit_the_flesh_sculptor.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/keskit_the_flesh_sculptor.txt rename to forge-gui/res/cardsfolder/k/keskit_the_flesh_sculptor.txt diff --git a/forge-gui/res/cardsfolder/upcoming/kinsbaile_courier.txt b/forge-gui/res/cardsfolder/k/kinsbaile_courier.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/kinsbaile_courier.txt rename to forge-gui/res/cardsfolder/k/kinsbaile_courier.txt diff --git a/forge-gui/res/cardsfolder/upcoming/kitesail_skirmisher.txt b/forge-gui/res/cardsfolder/k/kitesail_skirmisher.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/kitesail_skirmisher.txt rename to forge-gui/res/cardsfolder/k/kitesail_skirmisher.txt diff --git a/forge-gui/res/cardsfolder/upcoming/kodama_of_the_east_tree.txt b/forge-gui/res/cardsfolder/k/kodama_of_the_east_tree.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/kodama_of_the_east_tree.txt rename to forge-gui/res/cardsfolder/k/kodama_of_the_east_tree.txt diff --git a/forge-gui/res/cardsfolder/upcoming/krark_the_thumbless.txt b/forge-gui/res/cardsfolder/k/krark_the_thumbless.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/krark_the_thumbless.txt rename to forge-gui/res/cardsfolder/k/krark_the_thumbless.txt diff --git a/forge-gui/res/cardsfolder/upcoming/kwain_itinerant_meddler.txt b/forge-gui/res/cardsfolder/k/kwain_itinerant_meddler.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/kwain_itinerant_meddler.txt rename to forge-gui/res/cardsfolder/k/kwain_itinerant_meddler.txt diff --git a/forge-gui/res/cardsfolder/upcoming/laboratory_drudge.txt b/forge-gui/res/cardsfolder/l/laboratory_drudge.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/laboratory_drudge.txt rename to forge-gui/res/cardsfolder/l/laboratory_drudge.txt diff --git a/forge-gui/res/cardsfolder/upcoming/lathiel_the_bounteous_dawn.txt b/forge-gui/res/cardsfolder/l/lathiel_the_bounteous_dawn.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/lathiel_the_bounteous_dawn.txt rename to forge-gui/res/cardsfolder/l/lathiel_the_bounteous_dawn.txt diff --git a/forge-gui/res/cardsfolder/upcoming/liesa_shroud_of_dusk.txt b/forge-gui/res/cardsfolder/l/liesa_shroud_of_dusk.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/liesa_shroud_of_dusk.txt rename to forge-gui/res/cardsfolder/l/liesa_shroud_of_dusk.txt diff --git a/forge-gui/res/cardsfolder/upcoming/livio_oathsworn_sentinel.txt b/forge-gui/res/cardsfolder/l/livio_oathsworn_sentinel.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/livio_oathsworn_sentinel.txt rename to forge-gui/res/cardsfolder/l/livio_oathsworn_sentinel.txt diff --git a/forge-gui/res/cardsfolder/upcoming/maelstrom_colossus.txt b/forge-gui/res/cardsfolder/m/maelstrom_colossus.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/maelstrom_colossus.txt rename to forge-gui/res/cardsfolder/m/maelstrom_colossus.txt diff --git a/forge-gui/res/cardsfolder/upcoming/magus_of_the_order.txt b/forge-gui/res/cardsfolder/m/magus_of_the_order.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/magus_of_the_order.txt rename to forge-gui/res/cardsfolder/m/magus_of_the_order.txt diff --git a/forge-gui/res/cardsfolder/upcoming/malcolm_keen-eyed_navigator.txt b/forge-gui/res/cardsfolder/m/malcolm_keen-eyed_navigator.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/malcolm_keen-eyed_navigator.txt rename to forge-gui/res/cardsfolder/m/malcolm_keen-eyed_navigator.txt diff --git a/forge-gui/res/cardsfolder/upcoming/merchant_raiders.txt b/forge-gui/res/cardsfolder/m/merchant_raiders.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/merchant_raiders.txt rename to forge-gui/res/cardsfolder/m/merchant_raiders.txt diff --git a/forge-gui/res/cardsfolder/upcoming/meteoric_mace.txt b/forge-gui/res/cardsfolder/m/meteoric_mace.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/meteoric_mace.txt rename to forge-gui/res/cardsfolder/m/meteoric_mace.txt diff --git a/forge-gui/res/cardsfolder/upcoming/miara_thorn_of_the_glade.txt b/forge-gui/res/cardsfolder/m/miara_thorn_of_the_glade.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/miara_thorn_of_the_glade.txt rename to forge-gui/res/cardsfolder/m/miara_thorn_of_the_glade.txt diff --git a/forge-gui/res/cardsfolder/upcoming/mnemonic_deluge.txt b/forge-gui/res/cardsfolder/m/mnemonic_deluge.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/mnemonic_deluge.txt rename to forge-gui/res/cardsfolder/m/mnemonic_deluge.txt diff --git a/forge-gui/res/cardsfolder/upcoming/nadier_agent_of_the_duskenel.txt b/forge-gui/res/cardsfolder/n/nadier_agent_of_the_duskenel.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/nadier_agent_of_the_duskenel.txt rename to forge-gui/res/cardsfolder/n/nadier_agent_of_the_duskenel.txt diff --git a/forge-gui/res/cardsfolder/upcoming/nadiers_nightblade.txt b/forge-gui/res/cardsfolder/n/nadiers_nightblade.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/nadiers_nightblade.txt rename to forge-gui/res/cardsfolder/n/nadiers_nightblade.txt diff --git a/forge-gui/res/cardsfolder/upcoming/natural_reclamation.txt b/forge-gui/res/cardsfolder/n/natural_reclamation.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/natural_reclamation.txt rename to forge-gui/res/cardsfolder/n/natural_reclamation.txt diff --git a/forge-gui/res/cardsfolder/upcoming/necrotic_hex.txt b/forge-gui/res/cardsfolder/n/necrotic_hex.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/necrotic_hex.txt rename to forge-gui/res/cardsfolder/n/necrotic_hex.txt diff --git a/forge-gui/res/cardsfolder/upcoming/nevinyrral_urborg_tyrant.txt b/forge-gui/res/cardsfolder/n/nevinyrral_urborg_tyrant.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/nevinyrral_urborg_tyrant.txt rename to forge-gui/res/cardsfolder/n/nevinyrral_urborg_tyrant.txt diff --git a/forge-gui/res/cardsfolder/upcoming/nightshade_harvester.txt b/forge-gui/res/cardsfolder/n/nightshade_harvester.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/nightshade_harvester.txt rename to forge-gui/res/cardsfolder/n/nightshade_harvester.txt diff --git a/forge-gui/res/cardsfolder/upcoming/novellamental.txt b/forge-gui/res/cardsfolder/n/novellamental.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/novellamental.txt rename to forge-gui/res/cardsfolder/n/novellamental.txt diff --git a/forge-gui/res/cardsfolder/upcoming/numa_joraga_chieftain.txt b/forge-gui/res/cardsfolder/n/numa_joraga_chieftain.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/numa_joraga_chieftain.txt rename to forge-gui/res/cardsfolder/n/numa_joraga_chieftain.txt diff --git a/forge-gui/res/cardsfolder/upcoming/nymris_oonas_trickster.txt b/forge-gui/res/cardsfolder/n/nymris_oonas_trickster.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/nymris_oonas_trickster.txt rename to forge-gui/res/cardsfolder/n/nymris_oonas_trickster.txt diff --git a/forge-gui/res/cardsfolder/upcoming/obeka_brute_chronologist.txt b/forge-gui/res/cardsfolder/o/obeka_brute_chronologist.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/obeka_brute_chronologist.txt rename to forge-gui/res/cardsfolder/o/obeka_brute_chronologist.txt diff --git a/forge-gui/res/cardsfolder/upcoming/old_fogey.txt b/forge-gui/res/cardsfolder/o/old_fogey.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/old_fogey.txt rename to forge-gui/res/cardsfolder/o/old_fogey.txt diff --git a/forge-gui/res/cardsfolder/upcoming/opposition_agent.txt b/forge-gui/res/cardsfolder/o/opposition_agent.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/opposition_agent.txt rename to forge-gui/res/cardsfolder/o/opposition_agent.txt diff --git a/forge-gui/res/cardsfolder/upcoming/phyrexian_triniform.txt b/forge-gui/res/cardsfolder/p/phyrexian_triniform.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/phyrexian_triniform.txt rename to forge-gui/res/cardsfolder/p/phyrexian_triniform.txt diff --git a/forge-gui/res/cardsfolder/upcoming/plague_reaver.txt b/forge-gui/res/cardsfolder/p/plague_reaver.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/plague_reaver.txt rename to forge-gui/res/cardsfolder/p/plague_reaver.txt diff --git a/forge-gui/res/cardsfolder/upcoming/port_razer.txt b/forge-gui/res/cardsfolder/p/port_razer.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/port_razer.txt rename to forge-gui/res/cardsfolder/p/port_razer.txt diff --git a/forge-gui/res/cardsfolder/upcoming/prava_of_the_steel_legion.txt b/forge-gui/res/cardsfolder/p/prava_of_the_steel_legion.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/prava_of_the_steel_legion.txt rename to forge-gui/res/cardsfolder/p/prava_of_the_steel_legion.txt diff --git a/forge-gui/res/cardsfolder/upcoming/pride_of_the_perfect.txt b/forge-gui/res/cardsfolder/p/pride_of_the_perfect.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/pride_of_the_perfect.txt rename to forge-gui/res/cardsfolder/p/pride_of_the_perfect.txt diff --git a/forge-gui/res/cardsfolder/upcoming/profane_transfusion.txt b/forge-gui/res/cardsfolder/p/profane_transfusion.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/profane_transfusion.txt rename to forge-gui/res/cardsfolder/p/profane_transfusion.txt diff --git a/forge-gui/res/cardsfolder/upcoming/promise_of_tomorrow.txt b/forge-gui/res/cardsfolder/p/promise_of_tomorrow.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/promise_of_tomorrow.txt rename to forge-gui/res/cardsfolder/p/promise_of_tomorrow.txt diff --git a/forge-gui/res/cardsfolder/upcoming/radiant_serra_archangel.txt b/forge-gui/res/cardsfolder/r/radiant_serra_archangel.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/radiant_serra_archangel.txt rename to forge-gui/res/cardsfolder/r/radiant_serra_archangel.txt diff --git a/forge-gui/res/cardsfolder/upcoming/rakshasa_debaser.txt b/forge-gui/res/cardsfolder/r/rakshasa_debaser.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/rakshasa_debaser.txt rename to forge-gui/res/cardsfolder/r/rakshasa_debaser.txt diff --git a/forge-gui/res/cardsfolder/upcoming/rebbec_architect_of_ascension.txt b/forge-gui/res/cardsfolder/r/rebbec_architect_of_ascension.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/rebbec_architect_of_ascension.txt rename to forge-gui/res/cardsfolder/r/rebbec_architect_of_ascension.txt diff --git a/forge-gui/res/cardsfolder/upcoming/rejuvenating_springs.txt b/forge-gui/res/cardsfolder/r/rejuvenating_springs.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/rejuvenating_springs.txt rename to forge-gui/res/cardsfolder/r/rejuvenating_springs.txt diff --git a/forge-gui/res/cardsfolder/upcoming/reshape_the_earth.txt b/forge-gui/res/cardsfolder/r/reshape_the_earth.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/reshape_the_earth.txt rename to forge-gui/res/cardsfolder/r/reshape_the_earth.txt diff --git a/forge-gui/res/cardsfolder/upcoming/reyav_master_smith.txt b/forge-gui/res/cardsfolder/r/reyav_master_smith.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/reyav_master_smith.txt rename to forge-gui/res/cardsfolder/r/reyav_master_smith.txt diff --git a/forge-gui/res/cardsfolder/upcoming/rograkh_son_of_rohgahh.txt b/forge-gui/res/cardsfolder/r/rograkh_son_of_rohgahh.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/rograkh_son_of_rohgahh.txt rename to forge-gui/res/cardsfolder/r/rograkh_son_of_rohgahh.txt diff --git a/forge-gui/res/cardsfolder/upcoming/rootweaver_druid.txt b/forge-gui/res/cardsfolder/r/rootweaver_druid.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/rootweaver_druid.txt rename to forge-gui/res/cardsfolder/r/rootweaver_druid.txt diff --git a/forge-gui/res/cardsfolder/upcoming/sakashima_of_a_thousand_faces.txt b/forge-gui/res/cardsfolder/s/sakashima_of_a_thousand_faces.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/sakashima_of_a_thousand_faces.txt rename to forge-gui/res/cardsfolder/s/sakashima_of_a_thousand_faces.txt diff --git a/forge-gui/res/cardsfolder/upcoming/sakashimas_protege.txt b/forge-gui/res/cardsfolder/s/sakashimas_protege.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/sakashimas_protege.txt rename to forge-gui/res/cardsfolder/s/sakashimas_protege.txt diff --git a/forge-gui/res/cardsfolder/upcoming/sakashimas_will.txt b/forge-gui/res/cardsfolder/s/sakashimas_will.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/sakashimas_will.txt rename to forge-gui/res/cardsfolder/s/sakashimas_will.txt diff --git a/forge-gui/res/cardsfolder/upcoming/sengir_the_dark_baron.txt b/forge-gui/res/cardsfolder/s/sengir_the_dark_baron.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/sengir_the_dark_baron.txt rename to forge-gui/res/cardsfolder/s/sengir_the_dark_baron.txt diff --git a/forge-gui/res/cardsfolder/upcoming/seraphic_greatsword.txt b/forge-gui/res/cardsfolder/s/seraphic_greatsword.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/seraphic_greatsword.txt rename to forge-gui/res/cardsfolder/s/seraphic_greatsword.txt diff --git a/forge-gui/res/cardsfolder/upcoming/siani_eye_of_the_storm.txt b/forge-gui/res/cardsfolder/s/siani_eye_of_the_storm.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/siani_eye_of_the_storm.txt rename to forge-gui/res/cardsfolder/s/siani_eye_of_the_storm.txt diff --git a/forge-gui/res/cardsfolder/upcoming/slash_the_ranks.txt b/forge-gui/res/cardsfolder/s/slash_the_ranks.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/slash_the_ranks.txt rename to forge-gui/res/cardsfolder/s/slash_the_ranks.txt diff --git a/forge-gui/res/cardsfolder/upcoming/slurrk_all_ingesting.txt b/forge-gui/res/cardsfolder/s/slurrk_all_ingesting.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/slurrk_all_ingesting.txt rename to forge-gui/res/cardsfolder/s/slurrk_all_ingesting.txt diff --git a/forge-gui/res/cardsfolder/upcoming/soul_of_eternity.txt b/forge-gui/res/cardsfolder/s/soul_of_eternity.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/soul_of_eternity.txt rename to forge-gui/res/cardsfolder/s/soul_of_eternity.txt diff --git a/forge-gui/res/cardsfolder/upcoming/soulfire_eruption.txt b/forge-gui/res/cardsfolder/s/soulfire_eruption.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/soulfire_eruption.txt rename to forge-gui/res/cardsfolder/s/soulfire_eruption.txt diff --git a/forge-gui/res/cardsfolder/upcoming/spectator_seating.txt b/forge-gui/res/cardsfolder/s/spectator_seating.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/spectator_seating.txt rename to forge-gui/res/cardsfolder/s/spectator_seating.txt diff --git a/forge-gui/res/cardsfolder/upcoming/sphinx_of_the_second_sun.txt b/forge-gui/res/cardsfolder/s/sphinx_of_the_second_sun.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/sphinx_of_the_second_sun.txt rename to forge-gui/res/cardsfolder/s/sphinx_of_the_second_sun.txt diff --git a/forge-gui/res/cardsfolder/upcoming/staunch_throneguard.txt b/forge-gui/res/cardsfolder/s/staunch_throneguard.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/staunch_throneguard.txt rename to forge-gui/res/cardsfolder/s/staunch_throneguard.txt diff --git a/forge-gui/res/cardsfolder/upcoming/stumpsquall_hydra.txt b/forge-gui/res/cardsfolder/s/stumpsquall_hydra.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/stumpsquall_hydra.txt rename to forge-gui/res/cardsfolder/s/stumpsquall_hydra.txt diff --git a/forge-gui/res/cardsfolder/upcoming/sweet_gum_recluse.txt b/forge-gui/res/cardsfolder/s/sweet_gum_recluse.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/sweet_gum_recluse.txt rename to forge-gui/res/cardsfolder/s/sweet_gum_recluse.txt diff --git a/forge-gui/res/cardsfolder/upcoming/szats_will.txt b/forge-gui/res/cardsfolder/s/szats_will.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/szats_will.txt rename to forge-gui/res/cardsfolder/s/szats_will.txt diff --git a/forge-gui/res/cardsfolder/upcoming/target_minotaur.txt b/forge-gui/res/cardsfolder/t/target_minotaur.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/target_minotaur.txt rename to forge-gui/res/cardsfolder/t/target_minotaur.txt diff --git a/forge-gui/res/cardsfolder/upcoming/tevesh_szat_doom_of_fools.txt b/forge-gui/res/cardsfolder/t/tevesh_szat_doom_of_fools.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/tevesh_szat_doom_of_fools.txt rename to forge-gui/res/cardsfolder/t/tevesh_szat_doom_of_fools.txt diff --git a/forge-gui/res/cardsfolder/upcoming/thalisse_reverent_medium.txt b/forge-gui/res/cardsfolder/t/thalisse_reverent_medium.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/thalisse_reverent_medium.txt rename to forge-gui/res/cardsfolder/t/thalisse_reverent_medium.txt diff --git a/forge-gui/res/cardsfolder/upcoming/the_prismatic_piper.txt b/forge-gui/res/cardsfolder/t/the_prismatic_piper.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/the_prismatic_piper.txt rename to forge-gui/res/cardsfolder/t/the_prismatic_piper.txt diff --git a/forge-gui/res/cardsfolder/upcoming/timely_ward.txt b/forge-gui/res/cardsfolder/t/timely_ward.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/timely_ward.txt rename to forge-gui/res/cardsfolder/t/timely_ward.txt diff --git a/forge-gui/res/cardsfolder/upcoming/toggo_goblin_weaponsmith.txt b/forge-gui/res/cardsfolder/t/toggo_goblin_weaponsmith.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/toggo_goblin_weaponsmith.txt rename to forge-gui/res/cardsfolder/t/toggo_goblin_weaponsmith.txt diff --git a/forge-gui/res/cardsfolder/upcoming/tormod_the_desecrator.txt b/forge-gui/res/cardsfolder/t/tormod_the_desecrator.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/tormod_the_desecrator.txt rename to forge-gui/res/cardsfolder/t/tormod_the_desecrator.txt diff --git a/forge-gui/res/cardsfolder/upcoming/training_center.txt b/forge-gui/res/cardsfolder/t/training_center.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/training_center.txt rename to forge-gui/res/cardsfolder/t/training_center.txt diff --git a/forge-gui/res/cardsfolder/upcoming/trench_behemoth.txt b/forge-gui/res/cardsfolder/t/trench_behemoth.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/trench_behemoth.txt rename to forge-gui/res/cardsfolder/t/trench_behemoth.txt diff --git a/forge-gui/res/cardsfolder/upcoming/triumphant_reckoning.txt b/forge-gui/res/cardsfolder/t/triumphant_reckoning.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/triumphant_reckoning.txt rename to forge-gui/res/cardsfolder/t/triumphant_reckoning.txt diff --git a/forge-gui/res/cardsfolder/upcoming/trove_tracker.txt b/forge-gui/res/cardsfolder/t/trove_tracker.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/trove_tracker.txt rename to forge-gui/res/cardsfolder/t/trove_tracker.txt diff --git a/forge-gui/res/cardsfolder/upcoming/tuya_bearclaw.txt b/forge-gui/res/cardsfolder/t/tuya_bearclaw.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/tuya_bearclaw.txt rename to forge-gui/res/cardsfolder/t/tuya_bearclaw.txt diff --git a/forge-gui/res/cardsfolder/upcoming/undergrowth_stadium.txt b/forge-gui/res/cardsfolder/u/undergrowth_stadium.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/undergrowth_stadium.txt rename to forge-gui/res/cardsfolder/u/undergrowth_stadium.txt diff --git a/forge-gui/res/cardsfolder/upcoming/vault_of_champions.txt b/forge-gui/res/cardsfolder/v/vault_of_champions.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/vault_of_champions.txt rename to forge-gui/res/cardsfolder/v/vault_of_champions.txt diff --git a/forge-gui/res/cardsfolder/upcoming/volcanic_torrent.txt b/forge-gui/res/cardsfolder/v/volcanic_torrent.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/volcanic_torrent.txt rename to forge-gui/res/cardsfolder/v/volcanic_torrent.txt diff --git a/forge-gui/res/cardsfolder/upcoming/war_room.txt b/forge-gui/res/cardsfolder/w/war_room.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/war_room.txt rename to forge-gui/res/cardsfolder/w/war_room.txt diff --git a/forge-gui/res/cardsfolder/upcoming/wheel_of_misfortune.txt b/forge-gui/res/cardsfolder/w/wheel_of_misfortune.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/wheel_of_misfortune.txt rename to forge-gui/res/cardsfolder/w/wheel_of_misfortune.txt diff --git a/forge-gui/res/cardsfolder/upcoming/wrong_turn.txt b/forge-gui/res/cardsfolder/w/wrong_turn.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/wrong_turn.txt rename to forge-gui/res/cardsfolder/w/wrong_turn.txt diff --git a/forge-gui/res/cardsfolder/upcoming/wyleth_soul_of_steel.txt b/forge-gui/res/cardsfolder/w/wyleth_soul_of_steel.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/wyleth_soul_of_steel.txt rename to forge-gui/res/cardsfolder/w/wyleth_soul_of_steel.txt diff --git a/forge-gui/res/cardsfolder/upcoming/yurlok_of_scorch_thrash.txt b/forge-gui/res/cardsfolder/y/yurlok_of_scorch_thrash.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/yurlok_of_scorch_thrash.txt rename to forge-gui/res/cardsfolder/y/yurlok_of_scorch_thrash.txt diff --git a/forge-gui/res/cardsfolder/upcoming/zara_renegade_recruiter.txt b/forge-gui/res/cardsfolder/z/zara_renegade_recruiter.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/zara_renegade_recruiter.txt rename to forge-gui/res/cardsfolder/z/zara_renegade_recruiter.txt From 3eaf694ca9604789fbeb362e0dfe2ea5a69ae4d6 Mon Sep 17 00:00:00 2001 From: friarsol Date: Mon, 7 Dec 2020 22:05:28 -0500 Subject: [PATCH 29/97] Miglayout 5+ breaks quest WinLoseView --- forge-gui-desktop/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge-gui-desktop/pom.xml b/forge-gui-desktop/pom.xml index 94ec86fd6e7..b7847db08d4 100644 --- a/forge-gui-desktop/pom.xml +++ b/forge-gui-desktop/pom.xml @@ -132,7 +132,7 @@ com.miglayout miglayout-swing - 5.2 + 4.2 com.mortennobel From 63beb045f991f51253ded31aca2cfe3dff8d6f0b Mon Sep 17 00:00:00 2001 From: Michael Kamensky Date: Tue, 8 Dec 2020 10:51:39 +0300 Subject: [PATCH 30/97] - Basic AI logic components for Raiding Party. --- forge-ai/src/main/java/forge/ai/AiController.java | 3 +++ .../src/main/java/forge/ai/ability/ChooseCardAi.java | 12 ++++++++++++ .../src/main/java/forge/ai/ability/DestroyAllAi.java | 12 ++++++++++++ forge-gui/res/cardsfolder/r/raiding_party.txt | 7 ++++--- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index 2dabc751d06..b54c6344cbb 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -1802,6 +1802,9 @@ public class AiController { throw new UnsupportedOperationException(); } CardCollection result = new CardCollection(); + if (sa.hasParam("AIMaxAmount")) { + max = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("AIMaxAmount"), sa); + } switch(sa.getApi()) { case TwoPiles: // TODO: improve AI diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java index f8a48d2ec25..461e6b2e60c 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChooseCardAi.java @@ -130,6 +130,12 @@ public class ChooseCardAi extends SpellAbilityAi { return (ComputerUtilCard.evaluateCreatureList(aiCreatures) + minGain) < ComputerUtilCard .evaluateCreatureList(oppCreatures); + } else if (aiLogic.equals("OwnCard")) { + CardCollectionView ownChoices = CardLists.filter(choices, CardPredicates.isController(ai)); + if (ownChoices.isEmpty()) { + ownChoices = CardLists.filter(choices, CardPredicates.isControlledByAnyOf(ai.getAllies())); + } + return !ownChoices.isEmpty(); } return true; } @@ -156,6 +162,12 @@ public class ChooseCardAi extends SpellAbilityAi { choice = ComputerUtilCard.getBestAI(options); } else if ("WorstCard".equals(logic)) { choice = ComputerUtilCard.getWorstAI(options); + } else if ("OwnCard".equals(logic)) { + CardCollectionView ownChoices = CardLists.filter(options, CardPredicates.isController(ai)); + if (ownChoices.isEmpty()) { + ownChoices = CardLists.filter(options, CardPredicates.isControlledByAnyOf(ai.getAllies())); + } + choice = ComputerUtilCard.getBestAI(ownChoices); } else if (logic.equals("BestBlocker")) { if (!CardLists.filter(options, Presets.UNTAPPED).isEmpty()) { options = CardLists.filter(options, Presets.UNTAPPED); diff --git a/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java b/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java index 9a837bc1601..4a7c80ccdd8 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java @@ -2,10 +2,14 @@ package forge.ai.ability; import com.google.common.base.Predicate; +import com.google.common.base.Predicates; import forge.ai.*; +import forge.card.MagicColor; +import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CardCollection; import forge.game.card.CardLists; +import forge.game.card.CardPredicates; import forge.game.cost.Cost; import forge.game.keyword.Keyword; import forge.game.phase.PhaseType; @@ -106,6 +110,14 @@ public class DestroyAllAi extends SpellAbilityAi { } } + // Special handling for Raiding Party + if (logic.equals("RaidingParty")) { + int numAiCanSave = Math.min(CardLists.filter(ai.getCreaturesInPlay(), Predicates.and(CardPredicates.isColor(MagicColor.WHITE), CardPredicates.Presets.UNTAPPED)).size() * 2, ailist.size()); + int numOppsCanSave = Math.min(CardLists.filter(ai.getOpponents().getCreaturesInPlay(), Predicates.and(CardPredicates.isColor(MagicColor.WHITE), CardPredicates.Presets.UNTAPPED)).size() * 2, opplist.size()); + + return numOppsCanSave < opplist.size() && (ailist.size() - numAiCanSave < opplist.size() - numOppsCanSave); + } + // If effect is destroying creatures and AI is about to lose, activate effect anyway no matter what! if ((!CardLists.getType(opplist, "Creature").isEmpty()) && (ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)) && (ai.getGame().getCombat() != null && ComputerUtilCombat.lifeInSeriousDanger(ai, ai.getGame().getCombat()))) { diff --git a/forge-gui/res/cardsfolder/r/raiding_party.txt b/forge-gui/res/cardsfolder/r/raiding_party.txt index 7c1a88b1095..66bf60c1755 100644 --- a/forge-gui/res/cardsfolder/r/raiding_party.txt +++ b/forge-gui/res/cardsfolder/r/raiding_party.txt @@ -3,14 +3,15 @@ ManaCost:2 R Types:Enchantment S:Mode$ CantTarget | ValidCard$ Card.Self | ValidSource$ Card.White | Description$ CARDNAME can't be the target of white spells or abilities from white sources. A:AB$ RepeatEach | Cost$ Sac<1/Orc/Orc> | CostDesc$ Sacrifice an Orc: | RepeatPlayers$ Player | RepeatSubAbility$ ChooseCardsToTap | SubAbility$ DBDestroy | SpellDescription$ Each player may tap any number of untapped white creatures they control. For each creature tapped this way, that player chooses up to two Plains. Then destroy all Plains that weren’t chosen this way by any player. -SVar:ChooseCardsToTap:DB$ ChooseCard | Defined$ Remembered | MinAmount$ 0 | Amount$ NumCreatures | References$ NumCreatures | Choices$ Creature.untapped+White+RememberedPlayerCtrl | ChoiceTitle$ Choose any number of untapped white creatures you control | ChoiceZone$ Battlefield | RememberChosen$ True | SubAbility$ DBTap +SVar:ChooseCardsToTap:DB$ ChooseCard | Defined$ Remembered | MinAmount$ 0 | Amount$ NumCreatures | References$ NumCreatures,NumPlainsDiv2 | Choices$ Creature.untapped+White+RememberedPlayerCtrl | ChoiceTitle$ Choose any number of untapped white creatures you control | ChoiceZone$ Battlefield | RememberChosen$ True | AIMaxAmount$ NumPlainsDiv2 | SubAbility$ DBTap SVar:DBTap:DB$ Tap | Defined$ Remembered | SubAbility$ ChoosePlainsToSave -SVar:ChoosePlainsToSave:DB$ ChooseCard | Defined$ Remembered | MinAmount$ 0 | Amount$ TappedXTwo | References$ TappedXTwo | Choices$ Plains | ChoiceTitle$ Choose up to two Plains for each creature tapped | ChoiceZone$ Battlefield | ImprintChosen$ True | SubAbility$ DBCleanup +SVar:ChoosePlainsToSave:DB$ ChooseCard | Defined$ Remembered | MinAmount$ 0 | Amount$ TappedXTwo | References$ TappedXTwo | Choices$ Plains | ChoiceTitle$ Choose up to two Plains for each creature tapped | ChoiceZone$ Battlefield | ImprintChosen$ True | AILogic$ OwnCard | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True -SVar:DBDestroy:DB$ DestroyAll | ValidCards$ Plains.IsNotImprinted | SubAbility$ DBCleanImp | StackDescription$ None +SVar:DBDestroy:DB$ DestroyAll | ValidCards$ Plains.IsNotImprinted | SubAbility$ DBCleanImp | AILogic$ RaidingParty | StackDescription$ None SVar:DBCleanImp:DB$ Cleanup | ClearImprinted$ True SVar:NumCreatures:Count$Valid Creature.untapped+White+RememberedPlayerCtrl SVar:TappedXTwo:Count$Valid Creature.IsRemembered/Times.2 +SVar:NumPlainsDiv2:Count$Valid Plains.YouCtrl/HalfUp AI:RemoveDeck:Random SVar:NeedsToPlay:Plains.OppCtrl DeckNeeds:Type$Orc From 04ccb1d1067bc2fb59627bd350dad10a1793ef65 Mon Sep 17 00:00:00 2001 From: Michael Kamensky Date: Tue, 8 Dec 2020 10:57:34 +0300 Subject: [PATCH 31/97] - Fix imports. --- forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java b/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java index 4a7c80ccdd8..ba3b9e45afd 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java @@ -1,22 +1,20 @@ package forge.ai.ability; import com.google.common.base.Predicate; - import com.google.common.base.Predicates; import forge.ai.*; import forge.card.MagicColor; -import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CardCollection; import forge.game.card.CardLists; import forge.game.card.CardPredicates; +import forge.game.combat.Combat; import forge.game.cost.Cost; import forge.game.keyword.Keyword; import forge.game.phase.PhaseType; import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; -import forge.game.combat.Combat; public class DestroyAllAi extends SpellAbilityAi { From c9dab9c1d09705b29074d8df725913b7baad27d2 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Tue, 8 Dec 2020 19:21:01 +0800 Subject: [PATCH 32/97] Fix ChangeZoneAllEffect LTB triggers - fix Animate Dead + Worldgorger Dragon Combo Closes #887 --- .../java/forge/game/ability/effects/ChangeZoneAllEffect.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneAllEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneAllEffect.java index 911eab6e8dc..253031c67b5 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneAllEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneAllEffect.java @@ -226,8 +226,6 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect { } } - game.getTriggerHandler().resetActiveTriggers(false); - triggerList.triggerChangesZoneAll(game); // if Shuffle parameter exists, and any amount of cards were owned by From b26bba5b036131e3752da4d9abf4f319a4a8fef4 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Tue, 8 Dec 2020 07:03:24 -0500 Subject: [PATCH 33/97] living_hive.txt add CombatDamage$ True --- forge-gui/res/cardsfolder/l/living_hive.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/forge-gui/res/cardsfolder/l/living_hive.txt b/forge-gui/res/cardsfolder/l/living_hive.txt index 01a978ce006..dbbb555353b 100644 --- a/forge-gui/res/cardsfolder/l/living_hive.txt +++ b/forge-gui/res/cardsfolder/l/living_hive.txt @@ -3,8 +3,7 @@ ManaCost:6 G G Types:Creature Elemental Insect PT:6/6 K:Trample -T:Mode$ DamageDone | ValidSource$ Card.Self | Execute$ TrigToken | ValidTarget$ Player | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, create that many 1/1 green Insect creature tokens. -SVar:TrigToken:DB$ Token | TokenAmount$ X | TokenScript$ g_1_1_insect | TokenOwner$ You | LegacyImage$ g 1 1 insect mrd | References$ X +T:Mode$ DamageDone | ValidSource$ Card.Self | Execute$ TrigToken | CombatDamage$ True | ValidTarget$ Player | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, create that many 1/1 green Insect creature tokens. +SVar:TrigToken:DB$ Token | TokenAmount$ X | TokenScript$ g_1_1_insect | TokenOwner$ You | References$ X SVar:X:TriggerCount$DamageAmount -SVar:Picture:http://www.wizards.com/global/images/magic/general/living_hive.jpg Oracle:Trample\nWhenever Living Hive deals combat damage to a player, create that many 1/1 green Insect creature tokens. From ff9b21c1e5b5a243cb52a6e8fbde3e81b140a71f Mon Sep 17 00:00:00 2001 From: Northmoc Date: Tue, 8 Dec 2020 07:02:25 -0500 Subject: [PATCH 34/97] lathril_blade_of_the_elves.txt --- .../res/tokenscripts/lathril_blade_of_the_elves.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 forge-gui/res/tokenscripts/lathril_blade_of_the_elves.txt diff --git a/forge-gui/res/tokenscripts/lathril_blade_of_the_elves.txt b/forge-gui/res/tokenscripts/lathril_blade_of_the_elves.txt new file mode 100644 index 00000000000..f5e45e2d584 --- /dev/null +++ b/forge-gui/res/tokenscripts/lathril_blade_of_the_elves.txt @@ -0,0 +1,13 @@ +Name:Lathril, Blade of the Elves +ManaCost:2 B G +Types:Legendary Creature Elf Noble +PT:2/3 +K:Menace +T:Mode$ DamageDone | ValidSource$ Card.Self | CombatDamage$ True | ValidTarget$ Player | Execute$ TrigToken | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, create that many 1/1 green Elf Warrior creature tokens. +SVar:TrigToken:DB$ Token | TokenAmount$ X | TokenScript$ g_1_1_elf_warrior | TokenOwner$ You | References$ X +SVar:X:TriggerCount$DamageAmount +A:AB$ LoseLife | Cost$ T tapXType<10/Elf> | Defined$ Player.Opponent | LifeAmount$ 10 | SubAbility$ DBGainLife | SpellDescription$ Each opponent loses 10 life and you gain 10 life. +SVar:DBGainLife:DB$ GainLife | LifeAmount$ 10 +DeckHas:Ability$Token & Ability$LifeGain +DeckHints:Type$Elf +Oracle:Menace\nWhenever Lathril, Blade of the Elves deals combat damage to a player, create that many 1/1 green Elf Warrior creature tokens.\n{T}, tap ten untapped Elves you control: Each opponent loses 10 life and you gain 10 life. From f6ddda9b38d1bdf29ec88982b73f8bf99c8df3b0 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Tue, 8 Dec 2020 08:30:12 -0500 Subject: [PATCH 35/97] add chosen number to card detail pane --- forge-game/src/main/java/forge/game/card/Card.java | 1 + forge-game/src/main/java/forge/game/card/CardView.java | 7 +++++++ .../src/main/java/forge/trackable/TrackableProperty.java | 1 + forge-gui/src/main/java/forge/card/CardDetailUtil.java | 8 ++++++++ 4 files changed, 17 insertions(+) diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 1fa7a61ec7d..d0468ea3f41 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -1437,6 +1437,7 @@ public class Card extends GameEntity implements Comparable { } public final void setChosenNumber(final int i) { chosenNumber = i; + view.updateChosenNumber(this); } public final Card getExiledWith() { diff --git a/forge-game/src/main/java/forge/game/card/CardView.java b/forge-game/src/main/java/forge/game/card/CardView.java index a6487422fc2..c848700e2a6 100644 --- a/forge-game/src/main/java/forge/game/card/CardView.java +++ b/forge-game/src/main/java/forge/game/card/CardView.java @@ -306,6 +306,13 @@ public class CardView extends GameEntityView { set(TrackableProperty.ChosenType, c.getChosenType()); } + public String getChosenNumber() { + return get(TrackableProperty.ChosenNumber); + } + void updateChosenNumber(Card c) { + set(TrackableProperty.ChosenNumber, c.getChosenNumber().toString()); + } + public List getChosenColors() { return get(TrackableProperty.ChosenColors); } diff --git a/forge-game/src/main/java/forge/trackable/TrackableProperty.java b/forge-game/src/main/java/forge/trackable/TrackableProperty.java index a8ce01b8c2c..2bc1d95c063 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableProperty.java +++ b/forge-game/src/main/java/forge/trackable/TrackableProperty.java @@ -50,6 +50,7 @@ public enum TrackableProperty { ChosenType(TrackableTypes.StringType), ChosenColors(TrackableTypes.StringListType), ChosenCards(TrackableTypes.CardViewCollectionType), + ChosenNumber(TrackableTypes.StringType), ChosenPlayer(TrackableTypes.PlayerViewType), ChosenDirection(TrackableTypes.EnumType(Direction.class)), ChosenEvenOdd(TrackableTypes.EnumType(EvenOdd.class)), diff --git a/forge-gui/src/main/java/forge/card/CardDetailUtil.java b/forge-gui/src/main/java/forge/card/CardDetailUtil.java index af141b97c6e..1c994076c42 100644 --- a/forge-gui/src/main/java/forge/card/CardDetailUtil.java +++ b/forge-gui/src/main/java/forge/card/CardDetailUtil.java @@ -416,6 +416,14 @@ public class CardDetailUtil { area.append(")"); } + // chosen number + if (!card.getChosenNumber().isEmpty()) { + if (area.length() != 0) { + area.append("\n"); + } + area.append("(chosen number: ").append(card.getChosenNumber()).append(")"); + } + // chosen player if (card.getChosenPlayer() != null) { if (area.length() != 0) { From 3d55e4704a798e1151bd69ea335476524d67e36f Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Wed, 9 Dec 2020 13:08:43 +0100 Subject: [PATCH 36/97] CardFactoryUtil: make ColorsCtrl only check the players battlefield --- .../main/java/forge/game/card/CardFactoryUtil.java | 11 +---------- forge-gui/res/cardsfolder/c/chromatic_orrery.txt | 2 +- forge-gui/res/cardsfolder/c/coalition_victory.txt | 3 +-- forge-gui/res/cardsfolder/c/conquerors_flail.txt | 3 +-- forge-gui/res/cardsfolder/f/faeburrow_elder.txt | 2 +- forge-gui/res/cardsfolder/h/happily_ever_after.txt | 2 +- forge-gui/res/cardsfolder/r/ramos_dragon_engine.txt | 3 +-- .../res/cardsfolder/s/sisay_weatherlight_captain.txt | 2 +- forge-gui/res/cardsfolder/s/soul_of_ravnica.txt | 3 +-- 9 files changed, 9 insertions(+), 22 deletions(-) diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java index 1af50662bd9..255fdd911dd 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -1100,7 +1100,7 @@ public class CardFactoryUtil { if (sq[0].contains("ColorsCtrl")) { final String restriction = l[0].substring(11); final String[] rest = restriction.split(","); - final CardCollection list = CardLists.getValidCards(cc.getGame().getCardsInGame(), rest, cc, c, null); + final CardCollection list = CardLists.getValidCards(cc.getCardsIn(ZoneType.Battlefield), rest, cc, c, null); byte n = 0; for (final Card card : list) { n |= card.determineColor().getColor(); @@ -1540,15 +1540,6 @@ public class CardFactoryUtil { SpellAbility castSA = c.getCastSA(); return doXMath(castSA == null ? 0 : castSA.getPayingColors().countColors(), m, c); } - // Count$ColoredCreatures *a DOMAIN for creatures* - if (sq[0].contains("ColoredCreatures")) { - int mask = 0; - CardCollection someCards = CardLists.filter(cc.getCardsIn(ZoneType.Battlefield), Presets.CREATURES); - for (final Card crd : someCards) { - mask |= CardUtil.getColors(crd).getColor(); - } - return doXMath(ColorSet.fromMask(mask).countColors(), m, c); - } // Count$CardMulticolor.. if (sq[0].contains("CardMulticolor")) { diff --git a/forge-gui/res/cardsfolder/c/chromatic_orrery.txt b/forge-gui/res/cardsfolder/c/chromatic_orrery.txt index 68f184423fb..d364c3cb044 100755 --- a/forge-gui/res/cardsfolder/c/chromatic_orrery.txt +++ b/forge-gui/res/cardsfolder/c/chromatic_orrery.txt @@ -5,5 +5,5 @@ S:Mode$ Continuous | Affected$ You | ManaColorConversion$ Additive | WhiteConver SVar:NonStackingEffect:True A:AB$ Mana | Cost$ T | Produced$ C | Amount$ 5 | SpellDescription$ Add {C}{C}{C}{C}{C}. A:AB$ Draw | Cost$ 5 T | NumCards$ X | References$ X | SpellDescription$ Draw a card for each color among permanents you control. -SVar:X:Count$ColorsCtrl Permanent.YouCtrl+inZoneBattlefield +SVar:X:Count$ColorsCtrl Permanent Oracle:You may spend mana as though it were mana of any color.\n{T}: Add {C}{C}{C}{C}{C}.\n{5}, {T}: Draw a card for each color among permanents you control. diff --git a/forge-gui/res/cardsfolder/c/coalition_victory.txt b/forge-gui/res/cardsfolder/c/coalition_victory.txt index 2e9d71d3316..8b038c972bf 100644 --- a/forge-gui/res/cardsfolder/c/coalition_victory.txt +++ b/forge-gui/res/cardsfolder/c/coalition_victory.txt @@ -2,9 +2,8 @@ Name:Coalition Victory ManaCost:3 W U B R G Types:Sorcery A:SP$ WinsGame | Cost$ 3 W U B R G | Defined$ You | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ10 | References$ X,Y,Z | SpellDescription$ You win the game if you control a land of each basic land type and a creature of each color. -SVar:Z:Count$ColoredCreatures +SVar:Z:Count$ColorsCtrl Creature SVar:Y:Count$Domain SVar:X:SVar$Y/Plus.Z AI:RemoveDeck:Random -SVar:Picture:http://www.wizards.com/global/images/magic/general/coalition_victory.jpg Oracle:You win the game if you control a land of each basic land type and a creature of each color. diff --git a/forge-gui/res/cardsfolder/c/conquerors_flail.txt b/forge-gui/res/cardsfolder/c/conquerors_flail.txt index e1aad141b8c..a7936dda2c6 100644 --- a/forge-gui/res/cardsfolder/c/conquerors_flail.txt +++ b/forge-gui/res/cardsfolder/c/conquerors_flail.txt @@ -3,7 +3,6 @@ ManaCost:2 Types:Artifact Equipment S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ X | AddToughness$ X | References$ X | Description$ Equipped creature gets +1/+1 for each color among permanents you control. S:Mode$ CantBeCast | ValidCard$ Card | Condition$ PlayerTurn | Caster$ Opponent | IsPresent$ Card.Self+AttachedTo Creature | Description$ As long as Conqueror's Flail is attached to a creature, your opponents can't cast spells during your turn. -SVar:X:Count$ColorsCtrl Permanent.YouCtrl+inZoneBattlefield +SVar:X:Count$ColorsCtrl Permanent K:Equip:2 -SVar:Picture:http://www.wizards.com/global/images/magic/general/conquerors_flail.jpg Oracle:Equipped creature gets +1/+1 for each color among permanents you control.\nAs long as Conqueror's Flail is attached to a creature, your opponents can't cast spells during your turn.\nEquip {2} diff --git a/forge-gui/res/cardsfolder/f/faeburrow_elder.txt b/forge-gui/res/cardsfolder/f/faeburrow_elder.txt index 46ee607e76c..3b65c041662 100644 --- a/forge-gui/res/cardsfolder/f/faeburrow_elder.txt +++ b/forge-gui/res/cardsfolder/f/faeburrow_elder.txt @@ -4,7 +4,7 @@ Types:Creature Treefolk Druid PT:0/0 K:Vigilance S:Mode$ Continuous | Affected$ Card.Self | AddPower$ X | AddToughness$ X | Description$ CARDNAME gets +1/+1 for each color among permanents you control. -SVar:X:Count$ColorsCtrl Permanent.YouCtrl+inZoneBattlefield +SVar:X:Count$ColorsCtrl Permanent A:AB$ Mana | Cost$ T | Produced$ Special EachColorAmong_Permanent.YouCtrl | SpellDescription$ For each color among permanents you control, add one mana of that color. AI:RemoveDeck:All Oracle:Vigilance\nFaeburrow Elder gets +1/+1 for each color among permanents you control.\n{T}: For each color among permanents you control, add one mana of that color. diff --git a/forge-gui/res/cardsfolder/h/happily_ever_after.txt b/forge-gui/res/cardsfolder/h/happily_ever_after.txt index 30b5e69da1b..683fd942c34 100644 --- a/forge-gui/res/cardsfolder/h/happily_ever_after.txt +++ b/forge-gui/res/cardsfolder/h/happily_ever_after.txt @@ -6,7 +6,7 @@ SVar:TrigGainLife:DB$ GainLife | Defined$ Player | LifeAmount$ 5 | SubAbility$ D SVar:DBDraw:DB$ Draw | Defined$ Player | NumCards$ 1 T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | CheckSVar$ Z | SVarCompare$ EQ11 | LifeTotal$ You | LifeAmount$ GEW | References$ X,Y,Z,W | Execute$ TrigWin | TriggerDescription$ At the beginning of your upkeep, if there are five colors among permanents you control, there are six or more card types among permanents you control and/or cards in your graveyard, and your life total is greater than or equal to your starting life total, you win the game. SVar:TrigWin:DB$ WinsGame | Defined$ You -SVar:X:Count$ColorsCtrl Permanent.YouCtrl+inZoneBattlefield/LimitMax.5 +SVar:X:Count$ColorsCtrl Permanent/LimitMax.5 SVar:Y:Count$CardControllerTypes.Battlefield,Graveyard/LimitMax.6 SVar:Z:SVar$X/Plus.Y SVar:W:Count$YourStartingLife diff --git a/forge-gui/res/cardsfolder/r/ramos_dragon_engine.txt b/forge-gui/res/cardsfolder/r/ramos_dragon_engine.txt index 07b0157aee1..4c8af5bad34 100644 --- a/forge-gui/res/cardsfolder/r/ramos_dragon_engine.txt +++ b/forge-gui/res/cardsfolder/r/ramos_dragon_engine.txt @@ -5,7 +5,6 @@ PT:4/4 K:Flying T:Mode$ SpellCast | ValidActivatingPlayer$ You | Execute$ TrigPutCounter | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast a spell, put a +1/+1 counter on CARDNAME for each of that spell's colors. SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ X | References$ X -SVar:X:TriggeredCard$ColorsCtrl Card.Self +SVar:X:TriggeredCard$CardNumColors A:AB$ Mana | Cost$ SubCounter<5/P1P1> | Produced$ W W U U B B R R G G | ActivationLimit$ 1 | SpellDescription$ Add {W}{W}{U}{U}{B}{B}{R}{R}{G}{G}. Activate this ability only once each turn. -SVar:Picture:http://www.wizards.com/global/images/magic/general/ramos_dragon_engine.jpg Oracle:Flying\nWhenever you cast a spell, put a +1/+1 counter on Ramos, Dragon Engine for each of that spell's colors.\nRemove five +1/+1 counters from Ramos: Add {W}{W}{U}{U}{B}{B}{R}{R}{G}{G}. Activate this ability only once each turn. diff --git a/forge-gui/res/cardsfolder/s/sisay_weatherlight_captain.txt b/forge-gui/res/cardsfolder/s/sisay_weatherlight_captain.txt index d92106ac331..fb6bff9ed7d 100644 --- a/forge-gui/res/cardsfolder/s/sisay_weatherlight_captain.txt +++ b/forge-gui/res/cardsfolder/s/sisay_weatherlight_captain.txt @@ -3,7 +3,7 @@ ManaCost:2 W Types:Legendary Creature Human Soldier PT:2/2 S:Mode$ Continuous | Affected$ Card.Self | AddPower$ X | AddToughness$ X | References$ X | Description$ CARDNAME gets +1/+1 for each color among other legendary permanents you control. -SVar:X:Count$ColorsCtrl Permanent.YouCtrl+Other+Legendary+inZoneBattlefield +SVar:X:Count$ColorsCtrl Permanent.Other+Legendary A:AB$ ChangeZone | Cost$ W U B R G | Origin$ Library | Destination$ Battlefield | ChangeType$ Permanent.Legendary+cmcLTY | ChangeNum$ 1 | References$ Y | SpellDescription$ Search your library for a legendary permanent card with converted mana cost less than NICKNAME's power, put that card onto the battlefield, then shuffle your library. SVar:Y:Count$CardPower DeckHints:Type$Legendary diff --git a/forge-gui/res/cardsfolder/s/soul_of_ravnica.txt b/forge-gui/res/cardsfolder/s/soul_of_ravnica.txt index 8175bcba7fe..5e73aa3d942 100644 --- a/forge-gui/res/cardsfolder/s/soul_of_ravnica.txt +++ b/forge-gui/res/cardsfolder/s/soul_of_ravnica.txt @@ -5,7 +5,6 @@ PT:6/6 K:Flying A:AB$ Draw | Cost$ 5 U U | NumCards$ X | References$ X | SpellDescription$ Draw a card for each color among permanents you control. A:AB$ Draw | Cost$ 5 U U ExileFromGrave<1/CARDNAME> | ActivationZone$ Graveyard | NumCards$ X | References$ X | SpellDescription$ Draw a card for each color among permanents you control. -SVar:X:Count$ColorsCtrl Permanent.YouCtrl+inZoneBattlefield +SVar:X:Count$ColorsCtrl Permanent DeckNeeds:Color$White|Red|Green|Black -SVar:Picture:http://www.wizards.com/global/images/magic/general/soul_of_ravnica.jpg Oracle:Flying\n{5}{U}{U}: Draw a card for each color among permanents you control.\n{5}{U}{U}, Exile Soul of Ravnica from your graveyard: Draw a card for each color among permanents you control. From b96c974d3a45b58b9148120233668a55c9e871b3 Mon Sep 17 00:00:00 2001 From: friarsol Date: Wed, 9 Dec 2020 23:04:25 -0500 Subject: [PATCH 37/97] Update edition files to only use Set cards sheets --- forge-gui/res/editions/Aether Revolt.txt | 2 +- forge-gui/res/editions/Amonkhet Remastered.txt | 2 +- forge-gui/res/editions/Ikoria Lair of Behemoths.txt | 2 +- forge-gui/res/editions/Ixalan.txt | 2 +- forge-gui/res/editions/Kaladesh.txt | 2 +- forge-gui/res/editions/Magic 2021.txt | 2 +- forge-gui/res/editions/Rivals of Ixalan.txt | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/forge-gui/res/editions/Aether Revolt.txt b/forge-gui/res/editions/Aether Revolt.txt index 528323bd070..0d806127341 100644 --- a/forge-gui/res/editions/Aether Revolt.txt +++ b/forge-gui/res/editions/Aether Revolt.txt @@ -6,7 +6,7 @@ Code2=AER Type=Expansion MciCode=aer BoosterCovers=3 -Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand KLD +Booster=10 Common:fromSheet("AER cards"), 3 Uncommon:fromSheet("AER cards"), 1 RareMythic:fromSheet("AER cards"), 1 BasicLand KLD AdditionalSheetForFoils=fromSheet("AER Aether Revolt Inventions") AdditionalSetUnlockedInQuest=MPS_KLD diff --git a/forge-gui/res/editions/Amonkhet Remastered.txt b/forge-gui/res/editions/Amonkhet Remastered.txt index ea0bd1adc30..526c70c4403 100644 --- a/forge-gui/res/editions/Amonkhet Remastered.txt +++ b/forge-gui/res/editions/Amonkhet Remastered.txt @@ -3,7 +3,7 @@ Code=AKR Date=2020-08-13 Name=Amonkhet Remastered BoosterCovers=1 -Booster=10 Common, 3 Uncommon, 1 RareMythic +Booster=10 Common, 3 Uncommon, 1 RareMythic:!fromSheet("AKR buy a box") Type=Expansion [cards] diff --git a/forge-gui/res/editions/Ikoria Lair of Behemoths.txt b/forge-gui/res/editions/Ikoria Lair of Behemoths.txt index 1c9335ebd93..d952cb95b04 100644 --- a/forge-gui/res/editions/Ikoria Lair of Behemoths.txt +++ b/forge-gui/res/editions/Ikoria Lair of Behemoths.txt @@ -6,7 +6,7 @@ Code2=IKO MciCode=iko Type=Expansion BoosterCovers=3 -Booster=10 Common:!fromSheet("IKO Lands"), 3 Uncommon, 1 RareMythic, 1 fromSheet("IKO Lands") +Booster=10 Common:fromSheet("IKO cards"):!fromSheet("IKO Lands"), 3 Uncommon:fromSheet("IKO cards"), 1 RareMythic:fromSheet("IKO cards"), 1 fromSheet("IKO Lands") Prerelease=6 Boosters, 1 RareMythic+ [cards] diff --git a/forge-gui/res/editions/Ixalan.txt b/forge-gui/res/editions/Ixalan.txt index 83260821c73..0029ba49862 100644 --- a/forge-gui/res/editions/Ixalan.txt +++ b/forge-gui/res/editions/Ixalan.txt @@ -6,7 +6,7 @@ Code2=XLN Type=Expansion MciCode=xln BoosterCovers=5 -Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand +Booster=10 Common:fromSheet("XLN cards"), 3 Uncommon:fromSheet("XLN cards"), 1 RareMythic:fromSheet("XLN cards"), 1 BasicLand [cards] 1 U Adanto Vanguard diff --git a/forge-gui/res/editions/Kaladesh.txt b/forge-gui/res/editions/Kaladesh.txt index 6a4bd7e8358..8c6526c7e0a 100644 --- a/forge-gui/res/editions/Kaladesh.txt +++ b/forge-gui/res/editions/Kaladesh.txt @@ -6,7 +6,7 @@ Code2=KLD Type=Expansion MciCode=kld BoosterCovers=3 -Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand +Booster=10 Common:fromSheet("KLD cards"), 3 Uncommon:fromSheet("KLD cards"), 1 RareMythic:fromSheet("KLD cards"), 1 BasicLand AdditionalSheetForFoils=fromSheet("KLD Kaladesh Inventions") AdditionalSetUnlockedInQuest=MPS_KLD diff --git a/forge-gui/res/editions/Magic 2021.txt b/forge-gui/res/editions/Magic 2021.txt index 59608e8d811..fd44f5881af 100644 --- a/forge-gui/res/editions/Magic 2021.txt +++ b/forge-gui/res/editions/Magic 2021.txt @@ -4,7 +4,7 @@ Date=2020-06-04 Name=Core Set 2021 Type=Core BoosterCovers=3 -Booster=10 Common:!fromSheet(M21 Lands"), 3 Uncommon, 1 RareMythic, 1 fromSheet("M21 Lands") +Booster=10 Common:fromSheet("M21 cards"):!fromSheet("M21 Lands"), 3 Uncommon:fromSheet("M21 cards"), 1 RareMythic:fromSheet("M21 cards"), 1 fromSheet("M21 Lands") Prerelease=6 Boosters, 1 RareMythic+ ChaosDraftThemes=CORE_SET diff --git a/forge-gui/res/editions/Rivals of Ixalan.txt b/forge-gui/res/editions/Rivals of Ixalan.txt index 4e8864bd87d..adba859f598 100644 --- a/forge-gui/res/editions/Rivals of Ixalan.txt +++ b/forge-gui/res/editions/Rivals of Ixalan.txt @@ -6,7 +6,7 @@ Code2=RIX Type=Expansion MciCode=rix BoosterCovers=5 -Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand:fromSheet("RIX Basic Lands") +Booster=10 Common:fromSheet("RIX cards"), 3 Uncommon:fromSheet("RIX cards"), 1 RareMythic:fromSheet("RIX cards"), 1 BasicLand:fromSheet("RIX Basic Lands") TreatAsSmallSet=true [cards] From 56b5d532089786d1e8dc71ed612027ecc88c9380 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Thu, 10 Dec 2020 11:55:32 +0100 Subject: [PATCH 38/97] Cheat: fix cast cheat --- forge-gui/src/main/java/forge/player/PlayerControllerHuman.java | 1 + 1 file changed, 1 insertion(+) diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index 0d327e6f80b..1e1130d13ba 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -2515,6 +2515,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont // Human player is choosing targets for an ability // controlled by chosen player. sa.setActivatingPlayer(p); + sa.setSVar("IsCastFromPlayEffect", "True"); HumanPlay.playSaWithoutPayingManaCost(PlayerControllerHuman.this, getGame(), sa, true); } // playSa could fire some triggers From c4fb241ccec4349b6044c81a21f370857f957fe2 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Thu, 10 Dec 2020 21:53:51 +0800 Subject: [PATCH 39/97] Updated deckgen data -Austinio7116 --- forge-gui/res/deckgendecks/Modern.lda.dat | Bin 59442 -> 107522 bytes forge-gui/res/deckgendecks/Modern.raw.dat | Bin 53871 -> 97038 bytes forge-gui/res/deckgendecks/Pioneer.lda.dat | Bin 84239 -> 56905 bytes forge-gui/res/deckgendecks/Pioneer.raw.dat | Bin 88305 -> 49462 bytes forge-gui/res/deckgendecks/Standard.lda.dat | Bin 49636 -> 110993 bytes forge-gui/res/deckgendecks/Standard.raw.dat | Bin 40111 -> 111357 bytes 6 files changed, 0 insertions(+), 0 deletions(-) diff --git a/forge-gui/res/deckgendecks/Modern.lda.dat b/forge-gui/res/deckgendecks/Modern.lda.dat index 344572719060f8194ce8eb806eb452f7482e8e43..55c523f20a22318f47511ee70bb8a26c01ca0a6b 100644 GIT binary patch literal 107522 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 literal 59442 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 diff --git a/forge-gui/res/deckgendecks/Modern.raw.dat b/forge-gui/res/deckgendecks/Modern.raw.dat index a8bd2c837cdf585dd2699ab64a72fd9d78210b9c..23f4a0f9b09a8ff812f1074786542e2726be087c 100644 GIT binary patch literal 97038 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

40#y2A3a!9h~aJ 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 diff --git a/forge-gui/res/deckgendecks/Standard.lda.dat b/forge-gui/res/deckgendecks/Standard.lda.dat index 04bd607051f2a525d7bd4e1daca2559af414112f..91a567391a75761dbf761a70d8319c6a4d16c726 100644 GIT binary patch literal 110993 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
en&P2VS5OA%~Qo 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 literal 49636 zcmaid2Y8gl_V=cj4QX^xSrrQk2x4zBq|gG1Ndy%On`DzL+3bcbDToRRh@wanDbhtc zqS(vT3wW_(#jaNcuLZGtul@U-IaBt1dHH`nd3;FDnKNf*&YU)9=H2p*De^ch zE_UI+Bv)Iy%ax3OCA<`MWfl9wK2J5U{k0L$?rdlmhQr>DGJho6KJE3Rm+bK_PjV%U za3x3llYQ+iXr9hISQU5RC`t~dHpb&FQec@JL5NM6w<`zGuh(_iv*xqySYj0)o zZ$z&;6blEv&4f8D9Et_&A`?&_<*jMK%C7R(5Np#b`ZWU+dy`YftMg$`*{;)sT;2GaXSq{RDBKdU5nFxC3nzc~ z({GwsRZ~Y3Pu^GvL(Chllg!jFg~t5i(AH{vPR zgP-};T~~X%zoAgvB_ukv0iU;3P0x%4(=%?`m#r{zt9{Mb9JGL=y#ar%LYp>cWah!# zXB1ji6?TT-Qyun)nia~_v(I`s`;|WwN_M5cIUK5OvQA+nZAwOS2g>im_JWdTPR%D?2TZb$dT9x=3$~S=dIAUVSi05=nXjI zb^qz!`7xf0~Ai18QK5tkvFl^DW>3bi2s9p3! zI{E~mqfg+OAezTY7B;QhbOnAG0JS666qHMXn1EVMa{Y|!alVsDoN9?8_)ilp+kt%<{N2|y4vh=ad z_*tg#vWI)Ulk2?LN8t#BMEAYK&r$eM^t)7hC;DsqOYKZET-TubxaE>Nd*Vl-=9a=b z*92fiJcZ#XjEbaaM=OHVLGTO1b-p0%))A;>6#FCf{)QMF0-m;+gKN7DuIkrmOxz-B3{oZZ#WQYbwJ3AZSoOIJY*^h&0+ALUX~L>l5OOfa2aWDO0&+@KBUHLGdq-D?n*B}vp+qB5 z*y@-+(ulqb>smuiMrI}!-qQ;|YV`SKup>1XRTGUW3ZYP1%ZBJK4Z!_?cJukzd2kol zFw#cDu>0$kwzWZfk{YcGd;5C|YeRvKsL;=XrW}k7KWmh?gEZQ>uvc4<@zWmdJ?&Aw zgL)Qw+e4B5SOxeT7->xh+me`)1RH)1Trpq3Q{)TyYG9hwF0x_u80Qa$qTq962tG`h zc7G{pKD8hcy}do^$}1%@{#wt7Ao+00Hjsu*5*jv1jE#QpCw|wSOHw&}Pu_j^jhOP< z!%wghN~J&TkbrHi2cicv?iIhmUUsT#ff0a-jQ4XkhaYcEexps{xT~T*Z?jlQ#qNd& z|M|6dz&i?~Q&AYPf~UF>PGp0!%_t+5wcel+`MJ|R z9M^3zt6}uo1-mj_+bDa5&sY!bDv8=q-4*2RHbZcAw>FGURX(4Py6SLD%julgPs+;O ztR1nuQm7wxNGihEq7l{GZL1dee>&+pHH5sXHh+Dz4Vo(KDGK=O>(v_C@ZjVKR}7L_ z5sF0oH8B5rk!Iig{Ne)#E>twL%0l(g4o|T!=+_qTma%94^8AEJDQ zpdjaBru&_nRxJ5jp=FS!fRpG~hIIOm*$>Pe_q2lNV%7t~0j_8ap*vn>cfqs`_ZRr) zN$)x8$`}!>kA?k49bbRw{PX7bWcLB9lZEZqfX$33LB}{#o?O2;w(v&PQ|A%QE#Xj& z2oDMaZrjj2UYG$Rs4#5kY9Hsmx&+h!o<+;3t!C3F1 znB~c&4us#*hL>)_T&x2RvyhiqE{!-gcOt$v$kzK&aNNkqs}a(%VGR zSQPNKsmY(T``PBt|4P-Qil7C(P_MO~N?$B!!Z{lr!a2m$P@AMIw1%@Gp}#tREtY#k zolkk&Hk7a^B<`2|07!k5zxeH-Uv4@7mw5L=* zp=-`@pX4bzoi2$XoQ3ya9PaQc<2`=J?VY?UPEk17m52g;Vaz3Ur?#vODIXER%8;^vOpf(oUrOw?-YfcM2ToPkIn|A%>!Y3$sD9)1t$A|B!RFKd zVl3(`Q#Q8%qOR;x+Gur6!qv`v1T&zRYPEg+1&e4#k*ht_V{T}`5le_a3flk8_put&3vZSz9F?`#i#;hwJ zxrT9Q!p@hxSpaYau0X0I3M(ET{ok6@eZbqVZ&n?2gBMsEY9$dn?KE-;TcG*039utq z`|5pRe}9BZ6t|KL5G-5H#uWWGRh`#gjqZ)KU zs!d@Pd9hW({+Lp-H#Dtpn03Qb3N^3FPlg**tGqSv!nC|u@GvzAYHBP1xMU^XD9yYP z3CWWkuMmdcKbh94($@?Pt_C}~BxTd}56i$7F3RW_JPJ5V5f2Q6HXb&t-g-*nybu{X z%l>UGx)nwm{UJE(W5{GSBUty0j%g-h$JBlkJ@_5Z3JJn$NyP$yAe8!jfjXMo%9xIS zY&hMt<1IvvkSUy$1VgluhMCweq0k8c>sJNa8I3iI=HZw>O5x9NFLIY!$NJV>{Q1rY zhcnYrSI@W>)$o%iL5q6IXtc5i8~!n)!l8D!-N*}gMOp>|6>Wt29Udb+?A)k(nRl|c zmE*S2u>isk2p1O18N0KLv_Mo(yE7(oXVDl`Iwq?s6gmROnMgk(!FxqWXZvhJ$}5J$ z8uY*cA(sJhs&cp`o-qz5ityk>!3=zjysA*Z*Nj|}zd42!XIO8SZSChg7+4unc-=2; zpm>z1S5bmCYK;!o6>WIp`Hv?m?9K*zM9^1XPkLPre{JBhr-mLpQ(@*|$3~)F_*Oxm zM}+bcZ_U*0PyHR%8J12Jz=1OXxftD{mdJ*aOWp=011QBDHDUV7YbQ;e=w70_%o>dz z;oczD(wlzC&(o&AHTZW%p-umUWWxf0i9*APpLBL9WporZgIogtFJU&wPK|>63m@1UrpJSc1$# zod*j*{_s|7$dGABi$%l8QcqUHw;^qq|4vd$_7L?l1j;Z#+mkg5^WsDwe zq@iKINyN3jSz3MEZ&DFsUjj7({Gh)D`;r_Exw;lSnla_MSpZSjQH5~85V7=!fuiUc zA_f&R5^jRY^xK+bt7sNltGrDGUp6ENE%a*yNn)gxD`G9kCpmG35fmZvZwBkNo-%Ao zIIa>ecqr?^>?)vmcfUEeu!Zqpp3M!wV~xex#9Q_-i$mQBpGxU zY+H9$b>UO9Rj+wNNdw|MQbb3jl;!xhesk^1gOXT*Qw&~)?m7^UlK-eswqLmFlwLa8 z?=&>*^VLy@6`_z4%B?n>Qm@GJjiW@Qn(8f26d%lQ`%$r!gFyw!)HGS_%$Dm@pU%32 zeG!oq`$n>{`Cnyc|Mu3&+?)ofVv2jy+x~7&_A0uaOCq)27NllE!a9yaz^FJ_+wbBA*Q<{=atpG@=EQ;2F`R12&ceR;HqJgyuT~shVGXiIT0hL} z^>*aaL3e4kwVTzEfAO2IZ5*nY={X`;8>LA#I0jSe=mshry2tKOWhm zSU|hl7EBBxae(A)+!LeRpFMk-8bp^OR4~w4lbGO=Ao35|=-W{9V5#fi=#YzCg|w4S zY*uup8T*Y%((2^PzU+X6uZ{#5?*zb(t$?kEk1#sUzrOhG8y3DX_$=-XWe?@`bY24# z6c146?gEKn+)!JNf-(o;U>j9SltNdj4YYXeEsg7TFpJn6$ecxxo~`ux>LuMf57jS! z_x0yg&$*ZnVs0psy&}6Q(dJG+HhpNW@s(VEI{}~rD`O3m5*&`f!7bApdG_)@CLg?d zr|Kq$5|l`!!Ge3+%(2tVArBv@zWaKGgX*dM`zN{n2 zGvqF?A>@m2CP>7Dbfa@;N?D`fmO+q_?1{8Eqoj@Th2oNrww`iIaKb^t2XV(K^AQ;C zq~ok2vKqX|HcDxukryy_Wa{&i%Ab7iJb{a~%t6Ef*T9}&vtt#8YeMiC12iBreHJX* zO01^c1r`7j@Z~j#zuMvcMldJhP)6%F8*0{Q)SJ-3JH?t@x zkq8bWNOt4)lpU?o2d#!?&%!79zL_$3AP5^ibJgwObo}+ z1Z~u|gtebyL(avPh*0tnuD`DyGvYkR?r^QzqKyN*Zc(evZv? z(hau@`Cg@XZ4BT*hmxyEN<`n@H0h{7GSJ>m zg2V?a|KC$fpeCLwyV!J3+Wkd;yd{1k|EO>xBo2E8W~j~wsa4A7-ff}32Hm4Qfo@eT zzWAIW{A}1|WmneSw(r};Z*F0t#28x;cfp!R-x+mu*&@|j=iv~A5KilHUOu3RQY?C6 zSKn1|!Hg-lE6nbNF!X*Q0cHMr(!fJ0389>+imUN7}Oy*L}Ayl4=0zkzoy6_ zy@$gdh?7XP;E1)Z9vakhNz4c4shzuE{#i3uobcRy)goso<^vf%?5_BfmksMEF>T}; z;S{BTgCFWb%%UWG``Xt1Pi~Lnk<-KO0t)~N3vLaB2x1KNQVwC$(frJJ|9$&_S07fa z^;NzA{&jp(_R8Tp`7U2~hU>plxdI$TL@bH9`iZ?+yXcx@ZB)!60i@hCbmTXzT)Rj_v*Df72=%ZD}`G!(~ zVAOgFBehr;6P(-d+`|z7QOSeJDzPPJ)(HxB| z4=RD=6xmSohG7?yKBMwTQ8(m_*Leh-@qqB1E4-A0GTO{eQOqrMjP*pqM{gku9u_BI zl2ca%;N9ddu(Uu58|pMn<%ie=UbQi8IJrC?auyKfnmU6(c3RT3Xa22bsFT=gwneew zbT5mA5daes?KDc)HxIz+xa8V~-HBG2HnAAKGfvhpWP!n%H)7PQjZC&U*e5xl9GKFL zHl)1K$Rf&WGaNV=`M2O&wO&lgaRgq z0l9ems4eky`EbX=6a!Go+ya1$OGTV?Mu0^HUA4dOe*N5gBE$b02*xC?F_ci^j!Xa1_# z$u5RlLn(OdF~5#RXLveNKDuHWBcXND<+AmS(|0boYIlhN40ZxwkwobudC18Bq3YCV zg&SV)QTX_kc}yV=vCNNzu`g&6Pd3D?VUz?W)r)!u*{KaB2Ste90O}VIP6kn*C9x(i z-F)R^r!CPvmc`)O(jpHHBYY(Zl8CX|i`pJd@-QOJnWA6^B&f_%%c-x;e|Xy#mIGnC zFzyn0?2jKG_u4NXtKKYS2<6a2h%#|X&!aKJ%jq9qByt~ly)(qZ^O(ZOr?tBogRrNYV6AC{FRVYepm2D$|^zRR1@^? zHszH~R|4v2Zxthhrd;oB+unY+WcLu!2>U9V4viYbF&$2EYUH>#_gS`Ubxa;}VL}pA z+GWEZA06%9@~&zfSGj;0+(y3SR)nH3(@@(WJHK%C?F{SKQ90G$IqHwET+9*H0=-`<3~{KoV8< z!2*C%#Nk{3QG)G?#2sQ9c>5FGM5PIC+xf3um)$X4&qHM>N+qW-aSi^6H>UQK1&!LD zAxC8aAbuPf3WU8rWC=&Ng@UcIfFG1<1Li>dmM@<_aQ;nNzvhvih#|VVGzfX7GFM6W z=G>Rlj%nv8MKG)s^kIN+WsB)&zuGS$pwmNnIQOU*Ln(ruiH2Gff$OmBb2bfEBkqLL zrCK@~3D#3)3}eG)YrA~M(be;rGU@EGew>ctRs#-`b^hCilRF~N5rJ-o!b2%iREwzv z4b+p=mb3t(uI_3kiZJOgOJtppY*YTsr1g(^dtJ-YAm)RY%w1psh!YJecEJKbtMcU& z*eePRPKkY7b<9V+KwJbkD>BSkOC*-*2Gci_4SV!Tn%dDDfEFpPpWBytzhFgxj{&O%pp7VR;>9BL(81n9O(uQK|#?j8Qc^Yzt? zMIAmUJG1~~r)}O2PX*GKO4ZwNa)yOtNI=_Dc@`|{;t}UA^5LiXBEb&t|4o5n|H<&D zU}^u)o{({(YdJ{$i&C19Imos!glq-P416<@m~~-s3>?M>z>NAR{*rru&;5ZDy3;lkK zkoaSmw|GHYJO8NdNuRxB09T8DBF%Hf!51&OHc11L6=3DNy^^+;Q-B_NhpsaAHhV zZzsWx6?fJoe-<=!o_y310EtIC0WhK}y88nIN;hsLO0?;F|36Eg7QdnI&M0$-ZKq8O zCmz=;OiXFR>|zS+D}Aj#OJ#-)wW~ob_TjE!G(Ix3;pT|LRm3;dRIu2hA_xl>Et;xI zvICO-EPgZCuf;qC%Ez|}+YE&*ifa&dbhMv-rz4%doR zF{IPp?;-X+lfX*4Vd0PhjK6ZScEev)_)){mLGfR(wvkSH>C8sC4y!)y{`)OE*D0+0 zF>s^ESsIRG$r_)J>Sr+sD9j}jrW|_c^&*AXbsSRjIFrPDk!D52hC()_;TG|Kj7zec zEQweERQQan>|{T-U18W90a}pII#IdW767CdrJ1-jM0o;~{ZWB~9+d@?7}zWsn3wqc z=a=<4UyUM%W?G!SQg%+CUd;UPx4@9{XB1X;Noy#8R{#(+SD9)l3ljCAJa;=F@jcnO z1%Ojss+4JlKN)C}2-8Lmc;csb_>32eno%B$Hpe2kX)EDvft}s)qxiDKq?Je{BTEKG z$W4w%B;GiKVFN^6y~g@m{gieeEq&3G#AP;|fF7Ysocc6V6>}j>0)z>xFN(d7&~4I% zP5^X^qBSpF0K?9t!gpChB0OszK;x~KG=F^WE*gt%`0uJ0rqe(1jHouvX!WTJK&-j%_o$Ftqz*tr2)jC=>MPkH?8EcpURcpart4 z2bQd9Ib-tK2A~9ZZRdW4yMLLc0oui1bJiKhzBOyV1|)ncNiBQft>lX5S1|x?3U1?) zZ9}#Nkt{A9sJLip?pM1f9pe2b%-k4BVBu%|li#}X0Yh2E*%m<5m0FBK5S?tZ0BLAS zGv6`sy;~Q%SlDd9+5b(=-0?B1KH^7L>&?1p@U6e}>#7EnE0#eN zg3*fxKD84pXvDw`ay&C~u5zCfUZL7&@yiR~0P&0y3bkG01c9CQ5FUYS_&bWSMMa|VYa_d#JDdmmbC%bEzBC*ApPheKGCuCpLfFYJW53l0O!kbGV3eXy=iJ{w-Bziy(EFxu!3M{vK6 zQtmhw(dBs-WROo<>qLe6Rgs9jMZ$AVEnt<3NiC0S6c;+QqB*Sfv)0x^Wh71)eN#bX|=KM#}$7J+^U&z zog-Up$UFX`d*{Bz0FbT>)zAsOH2;-;U3kC#@`{^xzFw*+B#xC7*8Y26=ND@aXn@ZC zuDRol-8T##VgO1-tva=9&4&{HpxTRgS=>34bQfM7{&3#5bqXu5stK8^ z26ACA>?Xt*#I4_H&C>-%^Nlb;`pU*A-1CsAw>>-H_1{Kv6#xVg0s*53 zJyFO!n<}m{fZrux)^{%?&Hdv?4Up2}F1Y#k z`*R-Ncnbr_E%)IbuAbZq9CIkc-k$bDdG7%aX%b04N!qPPKhsb@^Ainl6*>V(CPZEj zgFygW10$&gJox7E?H^pn^f2h&!(f|Hv?*5@>J@HC#8Vu1$ZBhWTdri9sj3qHLI5l| znE3b88zX~8GHX~yc@I&%(}FrliPdoG`1dkCUBg(I&Sd_lyWpCXlUsvxSb5MkNamcp zyI}mF-Rn~>mVP`ffC>gI07{D>2tkz+M()F*k-tIqIPS^`Z!i0?Lh+T&rUX~6P|)c_Eh~ryHfT@lpHsM zL%k3-JUH%Nz6sQVi+|2oG%X=(H+1Znc$)YdsiST}{YaHflcjaWZ|jN{emRV}qBdtp zIvcNS|NY#Ec0ICjd!VTiXN8E>kQSrTy9k3}CRjAph8ko2JfoR{|Mth+}UQYs~~@Y3#!*1i3#257y!VA=b# z2Ap`02Bfq~QuF)OHl4rQ%K$vTb9pG-ipq>K+_R=_WS762%Wi+|_bx2|g4eqwovFEJ z78duDf=%Ra0zC*USto)PDFI@Mh2I!Qd9gxg=(p_*EfOU!kV885R zM0??%zLQ?keQ5th0!ZMJUKU^yxTA%@9j(z*QYD==-_4&o=#;(;Kwcb9MhA*55Khqf zDdwp#g1ZTIJ|$u{{Cs_{%v06qYe6JXCkd|#PFOhY`yGm~dt3;`oH&j(o|**%?CPWX zC1X$Z{d!)$YTC1~0|#6E=@uV~kiZfuyDSf&*zgfXA_Rp_Ey5v;0 zqYJSr*141%NW5dDZH^7O2M+6yhoH{sz82^r*ruzrai?4l~X zd3*0%b7<~A)W~{_r8m%U2nD(#Ay5AvZ7vkgS-K}Ub^8*9-mAKUE>0rdfl4MSL9WNu z79>cJ+?0G+8ju9^lYmQ()7!H<7aIb^S++F2D?x2JjY{EZ!>( zak%0x*m~^pCwI?eWeSnb84GuxR04{6YGZn(w^TlT#k7%s2-?8vS{0>R-W2U4+lWUX zTByWFGQaujihkE@y;$MqU;~Qh(#YvEDKHyWuEwgOB!cdEGd(ReiB&N=&bk7p9jFw; z13QR&XuaG8n?^6Fd-tr-s=usZA@Qb}h+`zm#_JzSyz@6L@HiC?Md^H#>XnTPus*-% z`!5Y=M+JT5iZc0DJV0P|LGRr}|83^}h=ty=m$hmC{BBC0bj65!G+n^%@E{$n0_@cj zQ%?PPgZ75I4TTO+N`Y<@4H$-dZfbX}CYCcVQ{?b&Lku?`gOs&3_cCvqbIxb@(aa>U zP`C>w51hT`i^m75)>-AUZiFhI#2?)Stv`wZE0jF0g+gY?cB3`&$l|%Ld{m?RNZcj~ zv`pzkLskTOUQX3Au)X7O@`%6@(xEb3yiyaVjra#ue+d3yqjihb>d!0*#f|M24_ET2O{qFhr|(zAo&~7kQ9Oa zc_w@OtFP^DIePlzTdM2Lc$o%V$e#y2UC>?14Nb&7lB;!}r2cbO`#f%ea0x}_L1c1J z-&qukMv(;9p@$9AT}8Jj#rmj#*M`x(y3r3cg3}m2T(p%It=YL}_b<1u*F6{E+?<3< z_#|-|dz`ezV}f~I-?DnhhSIGIq#YmtXN24ZtNJY%_IfcpGr~Brl7LTp#(x&%Fa1b$ znu<~vB=Y54EbX>o(bO$JDPT@H)SueNw83cJki5@YaM!x4?p0XqL*d!jCaF*KPG7jc z;O=ugoG~FL^fBCm_fA=UZ~1&CHjtoq#rbD#Kn)eE1U#jR+tU&$8J z|9ZcCO!iI#U=PJzU;#ju)oV54z%bOIQ{hwh-CXtW*Gw4UQaboB07s4}o3^#kb+m^8 zIBIbhTt|ZGdtWmtrQ2Q5ab^AX|D4PTCsNOF4;!0t)7f_IJ$6R^LmgkU#-+*BxAzVM zu;N0^i2EOpXKfq8J;DT*hbK3NTI~gH7A#t%DmklmK*G;Q0JwfR0ze0={(rr7-9?`; z8iq)z!1_8rE{V~d-6G@TdRqs~tZSI5IPNkQxpzEqMa2pt1%T3HWpZq&+0`8|$KoX= zycWhH=Ps}z<#OH?eOjN^sT}3*)A_wq*>xawW4TvHbDbhbxVrrE8!rm6S4xYJS|S0f zUh8@PqN`;1g(Oc&b4v$U#sfEAoR3MQl^f6S+!lF}hlkc$1n%DP&;@sAlrn%UG*{Eo z)h{BVJdkCNoVje&f!zwN8=fS>Tg^JPQ$_KME?lx9=i<3soW!8^6DGyyZ%|XT=($It zPn;nuD!`LVDa<=xI{S^L+(%Vs-Hjb62?preqAwWd94&a`oVhPN|DeK#Q4a*fBQo?n zm@)VQ*z(y*&%^E;sGEWl+w{UUWenqB9Wf>^Yx#7H&GGF z$JHdd)QEQgYQ^cDGa^Qn#G3Ii3Z3MtLJ8IBhke>}fBAK7jr2j_2a0=85Kz3^9Fjw| zp&%mQtA%tGi;h`n(eS!&|6jj7u9WvKhSU|6C;V6e1!ff(ej{!eIN=hrY6k$ z_4%RIH;dmeA^9U?cm)KLNgP-#v<hI#AS{I&A>**Lt< zVUE9Tlyi%{9U}dXAQ}^o94W8A1r2{nRp!(JfE5_t(Sr9fQ4GoNQy!stk~)93HOCPf z9nB-f(%=omRd`%7{@3enZ24AAR1OxM?!Ah%0Om^eV!;BFx|~4*DC?8F6{QR5$Pc0r z6ZH@@I#S8@;^E^(M(B9%keaQOeQXXiety{u_GU?j`SnO~E7XKU8=Eth@4w`2ZcR=u z?S0(p!ee#CAw2bJ;Ys=1rHj93yuS z@t!Z)THp8XM_)c)_6R_VI)l9T{X332<#O2t4WyfFu{QYi?wcRw--HXt4i3D*1v?L| z%-N@y=UdI5OIvud<5EVeL$^)oJY6CZGdm>dWsyg6?v~mYbJPV%p&C4=2xqSpi6VGn zcuYj1E-jzBJhx59HgWfC@q!>Wm%e>@SM-0^?^w23an&1#`t5X~lL|X9N0?yJM3jC~ zdv@M{m(w5YbBbz_i8Kppsp(;R+4r17zdZKr@=8Vk|B33%>c$BxU;fuUI@z8fj$PvJ z{7$>TKmPol8lEGcl`IV7s)A7mQ+u5L#eH+iRsWq)YKTf#!6l{YCbd2kBT+jDb zXhzcdOF&!p0~aRlUam-Vf_$Kmp@UnfAcY04Im*;vR3oxh$p|Bc9vpI%>m!S&=*T>SoGF; z1eMY;^0}&lA=Fco+_(#Dc)f71*H4W9+E_hry=Hmm?H?g+{5z9jz zUBnltp(p`c201NBxN1QEOHQuTX0~%lJMwu@Y~+0IoMBU`q9@mES!2 z1Gk{i0(ZZ}9iCETym2US1T^`&8@~x?3U+POkQwLu`Y_aSFPTIJCp^4y)KlCiae2P% z#R9YznLjRaP_*w=!y04HQnNnIlWb-jLG`utNlntbZ%P5=l80wO=YKtVUB ztQ8A(3Td3WbQf3vC@mX_8`Q}A(W{LdXYq4FX5K6fz+{?Q5DNflB^*=)ng<}zz-mT2+feP4F8HdK(kbLBjSr~&$r z)(+68#jA$>eDKhq1>6F%X+q2jd?rGd*xJ!_nWcEHU#lex8W_{wy#+uXaLkJwKke4| z$Dmj2y5{EIr$|+W=K3i4&fTlOytF%q#pH)2DZO=j-%l=B)xKY`k9W^Q!O1>xs$FL8 z8CbBW`IU0MX8ds9_sf>cQXM#|F#qD6iYg3U>qZ-rTim+C<2>f+nj0^_tE}f~TlBOi zaT>v0a2SBy6l9{N{yBQUO&^*Te5iOhAhDNZ)zSj2;vPB3TfbAuRm};7nE0Q))E2eYIte1|%q1Uh>DPZSxv0 zVgL&6>Afl1O?dKDHeKv`@wju2e^56~Q)**jh9_gj($%UdJt+(uOz-R9;<0QzzthO; z`j0g+rPeuf^P=CqkvB&*&a3ppJbH2K7EU?NJN4wu8nR$}VJ;_pv1PO6Cj!VTLk?B; zGPU@^>)-$D6-7)t10aQ~Mgb=*nrC&UZ)pxd+MP}jiNbE^c?MwQ;RQYwg_>H7amvppjd}Zl3 z@5&VhfkJ){N!Sp)aG`CG1rG#LIWR*eTFm>UnsN%OUmF0F#a$Bwk2K8qGFuA)NDLAz zb$BHU@AD|bY{8)U95{ z;ZH4dUB@B;)&vhyz3LVJ#?R7jQ{UNKv`lyAI#v>~1Cp~PU~!N8*ZlqYjk<+4VT*cw z+FX4L3qFNVC<4TD(^2?=v`#4UlLRby;8-h_g-3Tjdt?7{OJ^k^%J=~{64h^K0LMfTWL55*-d4jciH@X!$eX{>*7 z+EpF;dc^NCm?!FbtHuN1!I`fa7RK-tT2K9DOs$83mcPKm>2w;nE|g zq^Q(sTnP6SRCr*ci8p8JMS+ugMZlSEZrp>N@kYO0EIcPANHCKxknQaNUFU5F=!Yo| z1KfTDQpw6wYk9oB-?`ar;UHZ{anvO)n#w#Xl+|z?+TbmANz2j%{OY4N3joe;iO7T7 zAE&cnb;B)syp}1H&f%Y^u^`jxZ$APP`ue7&1u|RkwPH=ko6?Kdm*TkD8+X0Sf(z=} z@3sIaazz+N<-p=bpt*qOomsiA`;g&+C9!fUOtb@1+>&hz0EFXJE>VY3r!i~I_CU#$ne#tpbp}c5Bm!&XTydJDYXjHMUfFcsT505v{H?|jBON1( z*HKABZ3)NEG^lhHmaK6fc;%=br|ZtNQeEx-VQERX6I5q;D3L|nC60$YWAJLW zO3fGxku7i*kke4&*dyJ0Cv~h1$KZoj0<|KJLUUMx9JuMYF2I={6hJZR7r}; zQ}Aj69!>M2)H@IuFx*S;M^M*zL}>75|9K^mj}?SaJS_pU2LCy=&tDu$5I|oon|}JB z?Yn+44y}2r`^BGMF29sFk|1@8Bz4K+N3R-qD_a->=o)Cn<@AY103`61au>)hdE3(eQ>Tk2wAoC!lPbcU z#BVjoL|QVxf|iN5Q2XSkG?HmAjAk(_IgAGmla!OQx%uJu z@uLXffiGk{gT4URE9ubYb(8O+!TtA1O@ihb$4I&xKS}r?%eO(()oGq}Pxl#;{wYf% z=^pXQ6b^iF*r*-sdrqG?Wc|EC)psYn#U|?M3h5mh*}GukjIemB8|}b=_uk z>`;wS5Lt(}rtu1jp}*wN`Q3NEU8YcS`8_mpHTW@5*~P+LAMd_CV$@ffa*gI~iaq

&ot<~$xh>0NDId+b8q+PVGxi^P_g{)`UKO6n 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 diff --git a/forge-gui/res/deckgendecks/Standard.raw.dat b/forge-gui/res/deckgendecks/Standard.raw.dat index 2943612f3e3068449e46ae017d6f6a535819ca07..7f31f2a199ba313e7167fee03de18cdf5809d9f5 100644 GIT binary patch literal 111357 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 Ox*8>qqc9S61O6X0NlTFc literal 40111 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 From 479e4be56e69465669fbacfa98f0cb867144064a Mon Sep 17 00:00:00 2001 From: Gabriel Franco Date: Sat, 12 Dec 2020 17:37:37 +0000 Subject: [PATCH 40/97] Update worlds.txt --- forge-gui/res/quest/world/worlds.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/forge-gui/res/quest/world/worlds.txt b/forge-gui/res/quest/world/worlds.txt index d8b278d53a0..1ebdfaf1ac1 100644 --- a/forge-gui/res/quest/world/worlds.txt +++ b/forge-gui/res/quest/world/worlds.txt @@ -18,7 +18,7 @@ Name:Dominaria|Dir:1994-06 Legends|Sets:LEG, DOM|Banned:Arena of the Ancients; F Name:Terisiare: The Dark|Dir:1994-08 The Dark|Sets:DRK|Banned:Maze of Ith Name:Sarpadia|Dir:1994-11 Fallen Empires|Sets:FEM Name:Homelands|Dir:1995-10 Homelands|Sets:HML|Banned:Apocalypse Chime -Name:Terisiare: Ice Age|Dir:1996-05 Ice Age|Sets:ICE, ALL +Name:Terisiare: Ice Age|Dir:1996-05 Ice Age|Sets:ICE, ALL, CSP Name:Jamuraa: The Mirage Wars|Dir:1997-01 Mirage|Sets:MIR, VIS Name:Portal|Dir:1997-05 Portal|Sets:POR Name:Caliman|Dir:1998-06 Portal Second Age|Sets:PO2 @@ -32,6 +32,6 @@ Name:Random Core Set|Sets:LEA, LEB, 2ED, 3ED, 4ED, 5ED, 6ED, 7ED, 8ED, 9ED, 10E, Name:Ixalan|Sets:XLN, RIX Name:Innistrad|Sets:ISD, DKA, AVR, SOI, EMN Name:Kaladesh|Sets:AER, KLD, MPS, KLR -Name:Non-Block Sets|Sets:IKO, THB, ELD, WAR, RNA, GRN, DOM, HML, FEM, DRK, LEG, ATQ, ARN, JMP, CNS, CN2, BBD, MB1, MMA, MM2, EMA, MM3, IMA, A25, UMA, 2XM, ZNR +Name:Non-Block Sets|Sets:IKO, THB, ELD, WAR, RNA, GRN, DOM, HML, FEM, DRK, LEG, ATQ, ARN, JMP, CNS, CN2, BBD, MB1, MMA, MM2, EMA, MM3, IMA, A25, UMA, 2XM, ZNR, CMR Name:Tarkir|Sets:KTK, FRF, DTK Name:Alara|Sets:ALA, CFX, ARB \ No newline at end of file From 358409988385fa363b3b899a0ac33bf9fa1f22d5 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Mon, 14 Dec 2020 18:09:39 -0500 Subject: [PATCH 41/97] sengir_the_dark_baron.txt +TriggerZones +AI --- forge-gui/res/cardsfolder/s/sengir_the_dark_baron.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/forge-gui/res/cardsfolder/s/sengir_the_dark_baron.txt b/forge-gui/res/cardsfolder/s/sengir_the_dark_baron.txt index 6487b7c6666..abc7e5fb65e 100644 --- a/forge-gui/res/cardsfolder/s/sengir_the_dark_baron.txt +++ b/forge-gui/res/cardsfolder/s/sengir_the_dark_baron.txt @@ -6,8 +6,8 @@ K:Flying K:Partner T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.Other | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever another creature dies, put two +1/+1 counters on CARDNAME. SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 2 -T:Mode$ LosesGame | ValidPlayer$ Player.Other | Execute$ TrigGainLife | TriggerDescription$ Whenever another player loses the game, you gain life equal to that player's life total as the turn began. +T:Mode$ LosesGame | ValidPlayer$ Player.Other | TriggerZones$ Battlefield | Execute$ TrigGainLife | TriggerDescription$ Whenever another player loses the game, you gain life equal to that player's life total as the turn began. SVar:TrigGainLife:DB$ GainLife | Defined$ You | LifeAmount$ X | References$ X SVar:X:TriggeredPlayer$LifeStartedThisTurnWith -DeckHas:Ability$Counters +DeckHas:Ability$Counters & Ability$LifeGain Oracle:Whenever another creature dies, put two +1/+1 counters on Sengir, the Dark Baron.\nWhenever another player loses the game, you gain life equal to that player's life total as the turn began.\nPartner (You can have two commanders if both have partner.) From 9e492c9fe2ad7bb184d6d18c05c717d6cff8ebd5 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Tue, 15 Dec 2020 19:31:46 -0500 Subject: [PATCH 42/97] showdown_of_the_skalds.txt --- .../cardsfolder/upcoming/showdown_of_the_skalds.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/showdown_of_the_skalds.txt diff --git a/forge-gui/res/cardsfolder/upcoming/showdown_of_the_skalds.txt b/forge-gui/res/cardsfolder/upcoming/showdown_of_the_skalds.txt new file mode 100644 index 00000000000..8da01e09df3 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/showdown_of_the_skalds.txt @@ -0,0 +1,13 @@ +Name:Showdown of the Skalds +ManaCost:2 R W +Types:Enchantment Saga +K:Saga:3:TrigExile,TrigEffect,TrigEffect +SVar:TrigExile:DB$ Dig | Defined$ You | DigNum$ 4 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | SubAbility$ DBEffect | SpellDescription$ Exile the top four cards of your library. Until the end of your next turn, you may play those cards. +SVar:DBEffect:DB$ Effect | RememberObjects$ Remembered | StaticAbilities$ MayPlay | Duration$ UntilTheEndOfYourNextTurn | SubAbility$ DBCleanup | ForgetOnMoved$ Exile +SVar:MayPlay:Mode$ Continuous | Affected$ Card.IsRemembered | EffectZone$ Command | AffectedZone$ Exile | MayPlay$ True | Description$ Until the end of your next turn, you may play those cards. +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:TrigEffect:DB$ Effect | Triggers$ CastSpell | SpellDescription$ Whenever you cast a spell this turn, put a +1/+1 counter on target creature you control. +SVar:CastSpell:Mode$ SpellCast | ValidCard$ Card | ValidActivatingPlayer$ You | TriggerZones$ Command | Execute$ DBPutCounter | TriggerDescription$ Whenever you cast a spell this turn, put a +1/+1 counter on target creature you control. +SVar:DBPutCounter:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ 1 | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control +DeckHas:Ability$Counters +Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)\nI - Exile the top four cards of your library. Until the end of your next turn, you may play those cards.\nII, III - Whenever you cast a spell this turn, put a +1/+1 counter on target creature you control. From 610c8f8f389b74121e861314c34e5da1c8079116 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Tue, 15 Dec 2020 19:40:02 -0500 Subject: [PATCH 43/97] MDFC lands --- .../barkchannel_pathway_tidechannel_pathway.txt | 14 ++++++++++++++ .../blightstep_pathway_searstep_pathway.txt | 14 ++++++++++++++ .../darkbore_pathway_slitherbore_pathway.txt | 14 ++++++++++++++ .../hengegate_pathway_mistgate_pathway.txt | 14 ++++++++++++++ 4 files changed, 56 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/barkchannel_pathway_tidechannel_pathway.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/blightstep_pathway_searstep_pathway.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/darkbore_pathway_slitherbore_pathway.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/hengegate_pathway_mistgate_pathway.txt diff --git a/forge-gui/res/cardsfolder/upcoming/barkchannel_pathway_tidechannel_pathway.txt b/forge-gui/res/cardsfolder/upcoming/barkchannel_pathway_tidechannel_pathway.txt new file mode 100644 index 00000000000..cc88f72b313 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/barkchannel_pathway_tidechannel_pathway.txt @@ -0,0 +1,14 @@ +Name:Barkchannel Pathway +ManaCost:no cost +Types:Land +A:AB$ Mana | Cost$ T | Produced$ G | SpellDescription$ Add {G}. +AlternateMode:Modal +Oracle:Add {G}. + +ALTERNATE + +Name:Tidechannel Pathway +ManaCost:no cost +Types:Land +A:AB$ Mana | Cost$ T | Produced$ U | SpellDescription$ Add {U}. +Oracle:Add {U}. diff --git a/forge-gui/res/cardsfolder/upcoming/blightstep_pathway_searstep_pathway.txt b/forge-gui/res/cardsfolder/upcoming/blightstep_pathway_searstep_pathway.txt new file mode 100644 index 00000000000..912e253dacf --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/blightstep_pathway_searstep_pathway.txt @@ -0,0 +1,14 @@ +Name:Blightstep Pathway +ManaCost:no cost +Types:Land +A:AB$ Mana | Cost$ T | Produced$ B | SpellDescription$ Add {B}. +AlternateMode:Modal +Oracle:Add {B}. + +ALTERNATE + +Name:Searstep Pathway +ManaCost:no cost +Types:Land +A:AB$ Mana | Cost$ T | Produced$ R | SpellDescription$ Add {R}. +Oracle:Add {R}. diff --git a/forge-gui/res/cardsfolder/upcoming/darkbore_pathway_slitherbore_pathway.txt b/forge-gui/res/cardsfolder/upcoming/darkbore_pathway_slitherbore_pathway.txt new file mode 100644 index 00000000000..e40562d985a --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/darkbore_pathway_slitherbore_pathway.txt @@ -0,0 +1,14 @@ +Name:Darkbore Pathway +ManaCost:no cost +Types:Land +A:AB$ Mana | Cost$ T | Produced$ B | SpellDescription$ Add {B}. +AlternateMode:Modal +Oracle:Add {B}. + +ALTERNATE + +Name:Slitherbore Pathway +ManaCost:no cost +Types:Land +A:AB$ Mana | Cost$ T | Produced$ G | SpellDescription$ Add {G}. +Oracle:Add {G}. diff --git a/forge-gui/res/cardsfolder/upcoming/hengegate_pathway_mistgate_pathway.txt b/forge-gui/res/cardsfolder/upcoming/hengegate_pathway_mistgate_pathway.txt new file mode 100644 index 00000000000..27770d4e472 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/hengegate_pathway_mistgate_pathway.txt @@ -0,0 +1,14 @@ +Name:Hengegate Pathway +ManaCost:no cost +Types:Land +A:AB$ Mana | Cost$ T | Produced$ W | SpellDescription$ Add {W}. +AlternateMode:Modal +Oracle:Add {W}. + +ALTERNATE + +Name:Mistgate Pathway +ManaCost:no cost +Types:Land +A:AB$ Mana | Cost$ T | Produced$ U | SpellDescription$ Add {U}. +Oracle:Add {U}. From 2ccd690c2d054d3632fb612c7fcc4b858392c80c Mon Sep 17 00:00:00 2001 From: Northmoc Date: Thu, 17 Dec 2020 17:26:51 -0500 Subject: [PATCH 44/97] + SubAbility$ Cleanup --- forge-gui/res/cardsfolder/c/commune_with_lava.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge-gui/res/cardsfolder/c/commune_with_lava.txt b/forge-gui/res/cardsfolder/c/commune_with_lava.txt index 09be87b5a45..256327f9ebf 100644 --- a/forge-gui/res/cardsfolder/c/commune_with_lava.txt +++ b/forge-gui/res/cardsfolder/c/commune_with_lava.txt @@ -2,7 +2,7 @@ Name:Commune with Lava ManaCost:X R R Types:Instant A:SP$ Dig | Cost$ X R R | Defined$ You | DigNum$ X | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | References$ X | SubAbility$ DBMayPlay | SpellDescription$ Exile the top X cards of your library. Until the end of your next turn, you may play those cards. -SVar:DBMayPlay:DB$ Effect | StaticAbilities$ STCommuned | Duration$ UntilTheEndOfYourNextTurn | RememberObjects$ Remembered | ForgetOnMoved$ Exile +SVar:DBMayPlay:DB$ Effect | StaticAbilities$ STCommuned | Duration$ UntilTheEndOfYourNextTurn | RememberObjects$ Remembered | ForgetOnMoved$ Exile | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:STCommuned:Mode$ Continuous | Affected$ Card.IsRemembered | EffectZone$ Command | AffectedZone$ Exile | MayPlay$ True | Description$ Until the end of your next turn, you may play those cards. SVar:X:Count$xPaid From 3a15945a3773c94c4075fb7ff9d3bfe2cd441636 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Thu, 17 Dec 2020 17:27:25 -0500 Subject: [PATCH 45/97] KHM initial editions --- forge-gui/res/editions/Kaldheim.txt | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 forge-gui/res/editions/Kaldheim.txt diff --git a/forge-gui/res/editions/Kaldheim.txt b/forge-gui/res/editions/Kaldheim.txt new file mode 100644 index 00000000000..609a1597ce1 --- /dev/null +++ b/forge-gui/res/editions/Kaldheim.txt @@ -0,0 +1,46 @@ +[metadata] +Code=KHM +Date=2021-02-05 +Name=Kaldheim +Type=Expansion + +[cards] +15 M Halvar, God of Battle +142 R Magda, Brazen Outlaw +188 R Realmwalker +218 M Kaya the Inexorable +229 R Showdown of the Skalds +241 R Pyre of Heroes +251 R Barkchannel Pathway +252 R Blightstep Pathway +254 R Darkbore Pathway +260 R Hengegate Pathway +288 M Kaya the Inexorable +290 R Barkchannel Pathway +291 R Blightstep Pathway +292 R Darkbore Pathway +293 R Hengegate Pathway +299 M Halvar, God of Battle +312 R Magda, Brazen Outlaw +370 R Pyre of Heroes +374 R Valkyrie Harbinger +375 R Surtland Elementalist +376 R Cleaving Reaper +377 R Surtland Flinger +378 R Canopy Tactician +379 U Armed and Armored +380 U Starnhiem Aspirant +381 U Warchanter Skald +382 U Youthful Valyrie +383 U Absorb Identity +384 U Giant's Grasp +385 U Elderfang Ritualist +386 U Renegade Reaper +387 U Thornmantle Striker +388 U Bearded Axe +389 U Fire Giant's Fury +390 U Gilded Assault Cart +391 U Elven Ambush +392 U Gladewalker Ritualist +393 U Rampage of the Valkyries +399 R Realmwalker From cb6f4c14317373aedb4ad2549a8a8396fa04ec08 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Fri, 18 Dec 2020 21:36:59 +0100 Subject: [PATCH 46/97] IHasSVars interface to connect CardTraitBase -> Card -> CardState --- .../java/forge/ai/PlayerControllerAi.java | 4 +- .../main/java/forge/game/CardTraitBase.java | 93 ++++++++++++------- .../src/main/java/forge/game/IHasSVars.java | 20 ++++ .../forge/game/TriggerReplacementBase.java | 12 ++- .../forge/game/ability/AbilityFactory.java | 71 ++++++-------- .../java/forge/game/ability/AbilityUtils.java | 15 +-- .../ability/effects/AnimateEffectBase.java | 7 +- .../game/ability/effects/EffectEffect.java | 11 +-- .../game/ability/effects/PlayEffect.java | 10 +- .../src/main/java/forge/game/card/Card.java | 2 +- .../java/forge/game/card/CardFactory.java | 3 - .../main/java/forge/game/card/CardState.java | 3 +- .../java/forge/game/card/CounterEnumType.java | 2 + .../game/replacement/ReplacementHandler.java | 33 +++---- .../forge/game/spellability/SpellAbility.java | 6 +- .../SpellAbilityStackInstance.java | 7 +- .../StaticAbilityContinuous.java | 12 +-- .../forge/game/trigger/WrappedAbility.java | 8 +- .../upcoming/kaya_the_inexorable.txt | 17 ++++ 19 files changed, 178 insertions(+), 158 deletions(-) create mode 100644 forge-game/src/main/java/forge/game/IHasSVars.java create mode 100644 forge-gui/res/cardsfolder/upcoming/kaya_the_inexorable.txt diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java index 2105a24592f..3e2590964c0 100644 --- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java +++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java @@ -957,9 +957,7 @@ public class PlayerControllerAi extends PlayerController { final Ability emptyAbility = new AbilityStatic(source, cost, sa.getTargetRestrictions()) { @Override public void resolve() { } }; emptyAbility.setActivatingPlayer(player); emptyAbility.setTriggeringObjects(sa.getTriggeringObjects()); - for (String sVar : sa.getSVars()) { - emptyAbility.setSVar(sVar, sa.getSVar(sVar)); - } + emptyAbility.setSVars(sa.getSVars()); if (ComputerUtilCost.willPayUnlessCost(sa, player, cost, alreadyPaid, allPayers) && ComputerUtilCost.canPayCost(emptyAbility, player)) { ComputerUtil.playNoStack(player, emptyAbility, getGame()); // AI needs something to resolve to pay that cost return true; diff --git a/forge-game/src/main/java/forge/game/CardTraitBase.java b/forge-game/src/main/java/forge/game/CardTraitBase.java index b8e2dce51cd..cf98aedb023 100644 --- a/forge-game/src/main/java/forge/game/CardTraitBase.java +++ b/forge-game/src/main/java/forge/game/CardTraitBase.java @@ -21,15 +21,17 @@ import org.apache.commons.lang3.StringUtils; import com.google.common.collect.ImmutableList; import com.google.common.collect.Maps; -/** +/** * Base class for Triggers,ReplacementEffects and StaticAbilities. - * + * */ -public abstract class CardTraitBase extends GameObject implements IHasCardView { +public abstract class CardTraitBase extends GameObject implements IHasCardView, IHasSVars { /** The host card. */ protected Card hostCard; + private Card grantorCard = null; // card which grants the ability (equipment or owner of static ability that gave this one) + /** The map params. */ protected Map originalMapParams = Maps.newHashMap(), mapParams = Maps.newHashMap(); @@ -40,7 +42,7 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView { /** The suppressed. */ protected boolean suppressed = false; - protected Map sVars = Maps.newHashMap(); + protected Map sVars = Maps.newTreeMap(); protected Map intrinsicChangedTextColors = Maps.newHashMap(); protected Map intrinsicChangedTextTypes = Maps.newHashMap(); @@ -82,7 +84,7 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView { public boolean hasParam(String key) { return mapParams.containsKey(key); - } + } /** *

* Getter for the field mapParams. @@ -110,7 +112,7 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView { *

* Getter for the field hostCard. *

- * + * * @return a {@link forge.game.card.Card} object. */ public Card getHostCard() { @@ -133,7 +135,7 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView { *

* isSecondary. *

- * + * * @return a boolean. */ public final boolean isSecondary() { @@ -144,7 +146,7 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView { *

* matchesValid. *

- * + * * @param o * a {@link java.lang.Object} object. * @param valids @@ -164,7 +166,7 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView { /** * Sets the suppressed. - * + * * @param supp * the new suppressed */ @@ -174,7 +176,7 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView { /** * Checks if is suppressed. - * + * * @return true, if is suppressed */ public final boolean isSuppressed() { @@ -184,7 +186,7 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView { protected boolean meetsCommonRequirements(Map params) { final Player hostController = this.getHostCard().getController(); final Game game = hostController.getGame(); - + if (params.containsKey("Metalcraft")) { if ("True".equalsIgnoreCase(params.get("Metalcraft")) != hostController.hasMetalcraft()) return false; } @@ -212,7 +214,7 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView { if (params.containsKey("Blessing")) { if ("True".equalsIgnoreCase(params.get("Blessing")) != hostController.hasBlessing()) return false; } - + if (params.containsKey("Adamant")) { if (hostCard.getCastSA() == null) { return false; @@ -307,18 +309,18 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView { } } list = CardLists.getValidCards(list, sIsPresent.split(","), this.getHostCard().getController(), this.getHostCard(), null); - + final String rightString = presentCompare.substring(2); int right = AbilityUtils.calculateAmount(getHostCard(), rightString, this); final int left = list.size(); - + if (!Expressions.compare(left, presentCompare, right)) { return false; } - + } - + if (params.containsKey("IsPresent2")) { final String sIsPresent = params.get("IsPresent2"); String presentCompare = "GE1"; @@ -342,13 +344,13 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView { list.addAll(p.getCardsIn(presentZone)); } } - + list = CardLists.getValidCards(list, sIsPresent.split(","), this.getHostCard().getController(), this.getHostCard(), null); - + final String rightString = presentCompare.substring(2); int right = AbilityUtils.calculateAmount(getHostCard(), rightString, this); final int left = list.size(); - + if (!Expressions.compare(left, presentCompare, right)) { return false; } @@ -371,7 +373,7 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView { return false; } } - + if (params.containsKey("CheckSVar")) { final int sVar = AbilityUtils.calculateAmount(game.getCardState(this.getHostCard()), params.get("CheckSVar"), this); String comparator = "GE1"; @@ -385,7 +387,7 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView { return false; } } - + if (params.containsKey("ManaSpent")) { SpellAbility castSA = getHostCard().getCastSA(); if (castSA == null) { @@ -462,28 +464,29 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView { return CardView.get(hostCard); } - public String getSvarWithFallback(final String name) { - String var = sVars.get(name); - if (var == null) { - var = hostCard.getSVar(name); + protected IHasSVars getSVarFallback() { + if (getOriginalHost() != null) { + return getOriginalHost(); } - return var; + return getHostCard(); } + @Override public String getSVar(final String name) { - String var = sVars.get(name); - if (var == null) { - var = ""; + if (sVars.containsKey(name)) { + return sVars.get(name); + } else { + return getSVarFallback().getSVar(name); } - return var; } + @Override public boolean hasSVar(final String name) { - return sVars.containsKey(name); + return sVars.containsKey(name) || getSVarFallback().hasSVar(name); } public Integer getSVarInt(final String name) { - String var = sVars.get(name); + String var = this.getSVar(name); if (var != null) { try { return Integer.parseInt(var); @@ -493,12 +496,32 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView { return null; } + @Override public final void setSVar(final String name, final String value) { sVars.put(name, value); } - public Set getSVars() { - return sVars.keySet(); + @Override + public Map getSVars() { + return sVars; + } + + @Override + public void setSVars(Map newSVars) { + sVars = Maps.newTreeMap(); + sVars.putAll(newSVars); + } + + @Override + public void removeSVar(String var) { + sVars.remove(var); + } + + public Card getOriginalHost() { + return grantorCard; + } + public void setOriginalHost(final Card c) { + grantorCard = c; } public Map getChangedTextColors() { @@ -553,7 +576,7 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView { protected void copyHelper(CardTraitBase copy, Card host) { copy.originalMapParams = Maps.newHashMap(originalMapParams); copy.mapParams = Maps.newHashMap(originalMapParams); - copy.sVars = Maps.newHashMap(sVars); + copy.setSVars(sVars); // dont use setHostCard to not trigger the not copied parts yet copy.hostCard = host; } diff --git a/forge-game/src/main/java/forge/game/IHasSVars.java b/forge-game/src/main/java/forge/game/IHasSVars.java new file mode 100644 index 00000000000..f6effefb3f0 --- /dev/null +++ b/forge-game/src/main/java/forge/game/IHasSVars.java @@ -0,0 +1,20 @@ +package forge.game; + +import java.util.Map; + +public interface IHasSVars { + + public String getSVar(final String name); + + public boolean hasSVar(final String name); + //public Integer getSVarInt(final String name); + + public void setSVar(final String name, final String value); + public void setSVars(final Map newSVars); + + //public Set getSVars(); + + public Map getSVars(); + + public void removeSVar(final String var); +} diff --git a/forge-game/src/main/java/forge/game/TriggerReplacementBase.java b/forge-game/src/main/java/forge/game/TriggerReplacementBase.java index 8552db9f0ff..1ff5b94e3ae 100644 --- a/forge-game/src/main/java/forge/game/TriggerReplacementBase.java +++ b/forge-game/src/main/java/forge/game/TriggerReplacementBase.java @@ -19,13 +19,23 @@ public abstract class TriggerReplacementBase extends CardTraitBase implements II @Override public void setHostCard(final Card c) { - this.hostCard = c; + super.setHostCard(c); if (overridingAbility != null) { overridingAbility.setHostCard(c); } } + @Override + public void setOriginalHost(Card c) { + super.setOriginalHost(c); + if (overridingAbility != null) { + overridingAbility.setOriginalHost(c); + } + } + + + public Set getActiveZone() { return validHostZones; } diff --git a/forge-game/src/main/java/forge/game/ability/AbilityFactory.java b/forge-game/src/main/java/forge/game/ability/AbilityFactory.java index 2ddddf62ee5..d8b231bb6aa 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityFactory.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityFactory.java @@ -21,6 +21,7 @@ import com.google.common.base.Function; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import forge.card.CardStateName; +import forge.game.IHasSVars; import forge.game.ability.effects.CharmEffect; import forge.game.card.Card; import forge.game.card.CardState; @@ -102,7 +103,10 @@ public final class AbilityFactory { } public static final SpellAbility getAbility(final String abString, final Card card) { - return getAbility(abString, card.getCurrentState(), null); + return getAbility(abString, card, card.getCurrentState()); + } + public static final SpellAbility getAbility(final String abString, final Card card, final IHasSVars sVarHolder) { + return getAbility(abString, card.getCurrentState(), sVarHolder); } /** *

@@ -116,10 +120,10 @@ public final class AbilityFactory { * @return a {@link forge.game.spellability.SpellAbility} object. */ public static final SpellAbility getAbility(final String abString, final CardState state) { - return getAbility(abString, state, null); + return getAbility(abString, state, state); } - private static final SpellAbility getAbility(final String abString, final CardState state, final SpellAbility parent) { + private static final SpellAbility getAbility(final String abString, final CardState state, final IHasSVars sVarHolder) { Map mapParams; try { mapParams = AbilityFactory.getMapParams(abString); @@ -134,7 +138,7 @@ public final class AbilityFactory { throw new RuntimeException("AbilityFactory : getAbility -- no API in " + source + ": " + abString); } try { - return getAbility(mapParams, type, state, parent); + return getAbility(mapParams, type, state, sVarHolder); } catch (Error | Exception ex) { String msg = "AbilityFactory:getAbility: crash when trying to create ability "; Sentry.getContext().recordBreadcrumb( @@ -146,28 +150,24 @@ public final class AbilityFactory { } public static final SpellAbility getAbility(final Card hostCard, final String svar) { - return getAbility(hostCard.getCurrentState(), svar, null); + return getAbility(hostCard, svar, hostCard.getCurrentState()); } - public static final SpellAbility getAbility(final CardState state, final String svar) { - return getAbility(state, svar, null); + public static final SpellAbility getAbility(final Card hostCard, final String svar, final IHasSVars sVarHolder) { + return getAbility(hostCard.getCurrentState(), svar, sVarHolder); } - private static final SpellAbility getAbility(final CardState state, final String svar, final SpellAbility parent) { - if (!state.hasSVar(svar)) { + public static final SpellAbility getAbility(final CardState state, final String svar, final IHasSVars sVarHolder) { + if (!sVarHolder.hasSVar(svar)) { String source = state.getCard().getName(); throw new RuntimeException("AbilityFactory : getAbility -- " + source + " has no SVar: " + svar); } else { - return getAbility(state.getSVar(svar), state, parent); + return getAbility(sVarHolder.getSVar(svar), state, sVarHolder); } } - - public static final SpellAbility getAbility(final Map mapParams, AbilityRecordType type, final Card card, final SpellAbility parent) { - return getAbility(mapParams, type, card.getCurrentState(), parent); - } - public static final SpellAbility getAbility(final Map mapParams, AbilityRecordType type, final CardState state, final SpellAbility parent) { - return getAbility(type, type.getApiTypeOf(mapParams), mapParams, parseAbilityCost(state, mapParams, type), state, parent); + public static final SpellAbility getAbility(final Map mapParams, AbilityRecordType type, final CardState state, final IHasSVars sVarHolder) { + return getAbility(type, type.getApiTypeOf(mapParams), mapParams, parseAbilityCost(state, mapParams, type), state, sVarHolder); } @@ -184,12 +184,7 @@ public final class AbilityFactory { } public static final SpellAbility getAbility(AbilityRecordType type, ApiType api, Map mapParams, - Cost abCost,final Card card, final SpellAbility parent) { - return getAbility(type, api, mapParams, abCost, card.getCurrentState(), parent); - } - - public static final SpellAbility getAbility(AbilityRecordType type, ApiType api, Map mapParams, - Cost abCost,final CardState state, final SpellAbility parent) { + Cost abCost,final CardState state, final IHasSVars sVarHolder) { final Card hostCard = state.getCard(); TargetRestrictions abTgt = mapParams.containsKey("ValidTgts") ? readTarget(mapParams) : null; @@ -218,41 +213,36 @@ public final class AbilityFactory { if (spellAbility == null) { final StringBuilder msg = new StringBuilder(); msg.append("AbilityFactory : SpellAbility was not created for "); - msg.append(state.getName()); + msg.append(state.toString()); msg.append(". Looking for API: ").append(api); throw new RuntimeException(msg.toString()); } - // need to set Parent Early - if (parent != null && spellAbility instanceof AbilitySub) { - ((AbilitySub)spellAbility).setParent(parent); - } - // ********************************************* // set universal properties of the SpellAbility if (mapParams.containsKey("References")) { for (String svar : mapParams.get("References").split(",")) { - spellAbility.setSVar(svar, state.getSVar(svar)); + spellAbility.setSVar(svar, sVarHolder.getSVar(svar)); } } if (api == ApiType.DelayedTrigger && mapParams.containsKey("Execute")) { - spellAbility.setSVar(mapParams.get("Execute"), state.getSVar(mapParams.get("Execute"))); + spellAbility.setSVar(mapParams.get("Execute"), sVarHolder.getSVar(mapParams.get("Execute"))); } if (mapParams.containsKey("PreventionSubAbility")) { - spellAbility.setSVar(mapParams.get("PreventionSubAbility"), state.getSVar(mapParams.get("PreventionSubAbility"))); + spellAbility.setSVar(mapParams.get("PreventionSubAbility"), sVarHolder.getSVar(mapParams.get("PreventionSubAbility"))); } if (mapParams.containsKey("SubAbility")) { final String name = mapParams.get("SubAbility"); - spellAbility.setSubAbility(getSubAbility(state, name, spellAbility)); + spellAbility.setSubAbility(getSubAbility(state, name, sVarHolder)); } for (final String key : additionalAbilityKeys) { if (mapParams.containsKey(key) && spellAbility.getAdditionalAbility(key) == null) { - spellAbility.setAdditionalAbility(key, getSubAbility(state, mapParams.get(key), spellAbility)); + spellAbility.setAdditionalAbility(key, getSubAbility(state, mapParams.get(key), sVarHolder)); } } @@ -260,11 +250,10 @@ public final class AbilityFactory { final String key = "Choices"; if (mapParams.containsKey(key)) { List names = Lists.newArrayList(mapParams.get(key).split(",")); - final SpellAbility sap = spellAbility; spellAbility.setAdditionalAbilityList(key, Lists.transform(names, new Function() { @Override public AbilitySub apply(String input) { - return getSubAbility(state, input, sap); + return getSubAbility(state, input, sVarHolder); } })); } @@ -277,8 +266,8 @@ public final class AbilityFactory { } else if (mapParams.containsKey("SpellDescription")) { final StringBuilder sb = new StringBuilder(); - if (type != AbilityRecordType.SubAbility) { // SubAbilities don't have Costs or Cost - // descriptors + if (type != AbilityRecordType.SubAbility) { + // SubAbilities don't have Costs or Cost descriptors sb.append(spellAbility.getCostDescription()); } @@ -418,10 +407,10 @@ public final class AbilityFactory { * * @return a {@link forge.game.spellability.AbilitySub} object. */ - private static final AbilitySub getSubAbility(CardState state, String sSub, final SpellAbility parent) { + private static final AbilitySub getSubAbility(CardState state, String sSub, final IHasSVars sVarHolder) { - if (state.hasSVar(sSub)) { - return (AbilitySub) AbilityFactory.getAbility(state, sSub, parent); + if (sVarHolder.hasSVar(sSub)) { + return (AbilitySub) AbilityFactory.getAbility(state, sSub, sVarHolder); } System.out.println("SubAbility '"+ sSub +"' not found for: " + state.getName()); @@ -463,7 +452,7 @@ public final class AbilityFactory { SpellAbility rightAbility = rightState.getFirstAbility(); Map rightMap = Maps.newHashMap(rightAbility.getMapParams()); - AbilityRecordType rightType = AbilityRecordType.getRecordType(leftMap); + AbilityRecordType rightType = AbilityRecordType.getRecordType(rightMap); ApiType rightApi = leftType.getApiTypeOf(rightMap); rightMap.put("StackDescription", rightMap.get("SpellDescription")); rightMap.put("SpellDescription", ""); diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index 7c3dd5d85e7..34422ae5467 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -1901,16 +1901,6 @@ public class AbilityUtils { public static final String getSVar(final CardTraitBase ability, final String sVarName) { String val = ability.getSVar(sVarName); - if (StringUtils.isEmpty(val)) { - Card host = null; - if (ability instanceof SpellAbility) { - host = ((SpellAbility) ability).getOriginalHost(); - } - if (host == null) { - host = ability.getHostCard(); - } - val = host.getSVar(sVarName); - } if (!ability.isIntrinsic() || StringUtils.isEmpty(val)) { return val; } @@ -2016,9 +2006,8 @@ public class AbilityUtils { SpellAbility firstSpell = c.getFirstSpellAbility(); Map params = Maps.newHashMap(firstSpell.getMapParams()); - AbilityRecordType rc = AbilityRecordType.getRecordType(params); - ApiType api = rc.getApiTypeOf(params); - AbilitySub subAbility = (AbilitySub) AbilityFactory.getAbility(AbilityRecordType.SubAbility, api, params, null, c, null); + ApiType api = AbilityRecordType.getRecordType(params).getApiTypeOf(params); + AbilitySub subAbility = (AbilitySub) AbilityFactory.getAbility(AbilityRecordType.SubAbility, api, params, null, c.getCurrentState(), null); subAbility.setActivatingPlayer(sa.getActivatingPlayer()); subAbility.setHostCard(sa.getHostCard()); diff --git a/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java b/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java index ae6ffa205f3..68b50dfae39 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java +++ b/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java @@ -151,14 +151,17 @@ public abstract class AnimateEffectBase extends SpellAbilityEffect { // give abilities final List addedAbilities = Lists.newArrayList(); for (final String s : abilities) { - addedAbilities.add(AbilityFactory.getAbility(AbilityUtils.getSVar(sa, s), c)); + SpellAbility sSA = AbilityFactory.getAbility(c, s, sa); + sSA.setOriginalHost(source); + addedAbilities.add(sSA); } // Grant triggers final List addedTriggers = Lists.newArrayList(); for (final String s : triggers) { final Trigger parsedTrigger = TriggerHandler.parseTrigger(AbilityUtils.getSVar(sa, s), c, false); - parsedTrigger.setOverridingAbility(AbilityFactory.getAbility(AbilityUtils.getSVar(sa, parsedTrigger.getParam("Execute")), c)); + parsedTrigger.setOverridingAbility(AbilityFactory.getAbility(c, parsedTrigger.getParam("Execute"), sa)); + parsedTrigger.setOriginalHost(source); addedTriggers.add(parsedTrigger); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java b/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java index 60dc63538e0..081b0045a23 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java @@ -155,9 +155,7 @@ public class EffectEffect extends SpellAbilityEffect { // Grant abilities if (effectAbilities != null) { for (final String s : effectAbilities) { - final String actualAbility = AbilityUtils.getSVar(sa, s); - - final SpellAbility grantedAbility = AbilityFactory.getAbility(actualAbility, eff); + final SpellAbility grantedAbility = AbilityFactory.getAbility(eff, s, sa); eff.addSpellAbility(grantedAbility); grantedAbility.setIntrinsic(true); } @@ -166,11 +164,8 @@ public class EffectEffect extends SpellAbilityEffect { // Grant triggers if (effectTriggers != null) { for (final String s : effectTriggers) { - final String actualTrigger = AbilityUtils.getSVar(sa, s); - - final Trigger parsedTrigger = TriggerHandler.parseTrigger(actualTrigger, eff, true); - final String ability = AbilityUtils.getSVar(sa, parsedTrigger.getParam("Execute")); - parsedTrigger.setOverridingAbility(AbilityFactory.getAbility(ability, eff)); + final Trigger parsedTrigger = TriggerHandler.parseTrigger(AbilityUtils.getSVar(sa, s), eff, true); + parsedTrigger.setOverridingAbility(AbilityFactory.getAbility(eff, parsedTrigger.getParam("Execute"), sa)); parsedTrigger.setActiveZone(EnumSet.of(ZoneType.Command)); parsedTrigger.setIntrinsic(true); eff.addTrigger(parsedTrigger); diff --git a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java index 65ef6e1f37a..5d8d4782172 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java @@ -7,6 +7,7 @@ import org.apache.commons.lang3.StringUtils; import com.google.common.base.Predicate; import com.google.common.base.Predicates; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @@ -76,15 +77,12 @@ public class PlayEffect extends SpellAbilityEffect { CardCollection showCards = new CardCollection(); if (sa.hasParam("Valid")) { - ZoneType zone = ZoneType.Hand; - if (sa.hasParam("ValidZone")) { - zone = ZoneType.smartValueOf(sa.getParam("ValidZone")); - } + List zones = sa.hasParam("ValidZone") ? ZoneType.listValueOf(sa.getParam("ValidZone")) : ImmutableList.of(ZoneType.Hand); tgtCards = new CardCollection( - AbilityUtils.filterListByType(game.getCardsIn(zone), sa.getParam("Valid"), sa) + AbilityUtils.filterListByType(game.getCardsIn(zones), sa.getParam("Valid"), sa) ); if ( sa.hasParam("ShowCards") ) { - showCards = new CardCollection(AbilityUtils.filterListByType(game.getCardsIn(zone), sa.getParam("ShowCards"), sa)); + showCards = new CardCollection(AbilityUtils.filterListByType(game.getCardsIn(zones), sa.getParam("ShowCards"), sa)); } } else if (sa.hasParam("AnySupportedCard")) { diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index d0468ea3f41..a5180904bfb 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -80,7 +80,7 @@ import io.sentry.event.BreadcrumbBuilder; * @author Forge * @version $Id$ */ -public class Card extends GameEntity implements Comparable { +public class Card extends GameEntity implements Comparable, IHasSVars { private final Game game; private final IPaperCard paperCard; diff --git a/forge-game/src/main/java/forge/game/card/CardFactory.java b/forge-game/src/main/java/forge/game/card/CardFactory.java index c2cab603c52..d8e0c191986 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactory.java +++ b/forge-game/src/main/java/forge/game/card/CardFactory.java @@ -540,9 +540,6 @@ public class CardFactory { to.setActivatingPlayer(p, lki); } - for (String sVar : from.getSVars()) { - to.setSVar(sVar, from.getSVar(sVar)); - } //to.changeText(); } diff --git a/forge-game/src/main/java/forge/game/card/CardState.java b/forge-game/src/main/java/forge/game/card/CardState.java index 6563317225b..f304cfb409d 100644 --- a/forge-game/src/main/java/forge/game/card/CardState.java +++ b/forge-game/src/main/java/forge/game/card/CardState.java @@ -26,6 +26,7 @@ import forge.card.mana.ManaCostParser; import forge.game.CardTraitBase; import forge.game.ForgeScript; import forge.game.GameObject; +import forge.game.IHasSVars; import forge.game.card.CardView.CardStateView; import forge.game.keyword.Keyword; import forge.game.keyword.KeywordCollection; @@ -46,7 +47,7 @@ import java.util.Map; import io.sentry.Sentry; import io.sentry.event.BreadcrumbBuilder; -public class CardState extends GameObject { +public class CardState extends GameObject implements IHasSVars { private String name = ""; private CardType type = new CardType(false); private ManaCost manaCost = ManaCost.NO_COST; diff --git a/forge-game/src/main/java/forge/game/card/CounterEnumType.java b/forge-game/src/main/java/forge/game/card/CounterEnumType.java index 722180488e4..dc6b0409aa7 100644 --- a/forge-game/src/main/java/forge/game/card/CounterEnumType.java +++ b/forge-game/src/main/java/forge/game/card/CounterEnumType.java @@ -123,6 +123,8 @@ public enum CounterEnumType { GEM("GEM", 255, 99, 251), + GHOSTFORM("GHSTF", 223, 0, 254), + GLYPH("GLYPH", 184, 202, 199), GOLD("GOLD", 248, 191, 0), diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java index 92af2439f71..9842d8ca356 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java @@ -288,34 +288,25 @@ public class ReplacementHandler { host = game.getCardState(host); } - if (mapParams.containsKey("ReplaceWith")) { + if (replacementEffect.getOverridingAbility() == null && mapParams.containsKey("ReplaceWith")) { final String effectSVar = mapParams.get("ReplaceWith"); - final String effectAbString = host.getSVar(effectSVar); // TODO: the source of replacement effect should be the source of the original effect - effectSA = AbilityFactory.getAbility(effectAbString, host); + effectSA = AbilityFactory.getAbility(host, effectSVar, replacementEffect); + //replacementEffect.setOverridingAbility(effectSA); //effectSA.setTrigger(true); - - SpellAbility tailend = effectSA; - do { - replacementEffect.setReplacingObjects(runParams, tailend); - //set original Params to update them later - tailend.setReplacingObject(AbilityKey.OriginalParams, runParams); - tailend = tailend.getSubAbility(); - } while(tailend != null); - - } - else if (replacementEffect.getOverridingAbility() != null) { + } else if (replacementEffect.getOverridingAbility() != null) { effectSA = replacementEffect.getOverridingAbility(); - SpellAbility tailend = effectSA; - do { - replacementEffect.setReplacingObjects(runParams, tailend); - //set original Params to update them later - tailend.setReplacingObject(AbilityKey.OriginalParams, runParams); - tailend = tailend.getSubAbility(); - } while(tailend != null); } if (effectSA != null) { + SpellAbility tailend = effectSA; + do { + replacementEffect.setReplacingObjects(runParams, tailend); + //set original Params to update them later + tailend.setReplacingObject(AbilityKey.OriginalParams, runParams); + tailend = tailend.getSubAbility(); + } while(tailend != null); + effectSA.setLastStateBattlefield(game.getLastStateBattlefield()); effectSA.setLastStateGraveyard(game.getLastStateGraveyard()); if (replacementEffect.isIntrinsic()) { diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java index 2345598569d..227a81902ee 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -92,7 +92,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit private Player activatingPlayer = null; private Player targetingPlayer = null; - private Card grantorCard = null; // card which grants the ability (equipment or owner of static ability that gave this one) private SpellAbility grantorOriginal = null; private StaticAbility grantorStatic = null; @@ -369,11 +368,8 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit return this.isAlternativeCost(AlternativeCost.Cycling); } - public Card getOriginalHost() { - return grantorCard; - } public void setOriginalHost(final Card c) { - grantorCard = c; + super.setOriginalHost(c); if (subAbility != null) { subAbility.setOriginalHost(c); } diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbilityStackInstance.java b/forge-game/src/main/java/forge/game/spellability/SpellAbilityStackInstance.java index 747393bef06..3a5c171ca3d 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbilityStackInstance.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbilityStackInstance.java @@ -39,6 +39,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; /** @@ -141,10 +142,10 @@ public class SpellAbilityStackInstance implements IIdentifiable, IHasCardView { } // We probably should be storing SA svars too right? if (!sa.isWrapper()) { - for (final String store : sa.getSVars()) { - final String value = source.getSVar(store); + for (final Entry e : sa.getSVars().entrySet()) { + final String value = e.getValue(); if (!StringUtils.isEmpty(value)) { - storedSVars.put(store, value); + storedSVars.put(e.getKey(), value); } } } diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java index 6d0c1a729f6..48676613425 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java @@ -728,7 +728,7 @@ public final class StaticAbilityContinuous { abilty = TextUtil.fastReplace(abilty, "ConvertedManaCost", costcmc); } if (abilty.startsWith("AB") || abilty.startsWith("ST")) { // grant the ability - final SpellAbility sa = AbilityFactory.getAbility(abilty, affectedCard); + final SpellAbility sa = AbilityFactory.getAbility(abilty, affectedCard, stAb); sa.setIntrinsic(false); sa.setOriginalHost(hostCard); addedAbilities.add(sa); @@ -790,15 +790,10 @@ public final class StaticAbilityContinuous { // with that the TargetedCard does not need the Svars added to them anymore // but only do it if the trigger doesn't already have a overriding ability if (actualTrigger.hasParam("Execute") && actualTrigger.getOverridingAbility() == null) { - String svar = AbilityUtils.getSVar(stAb, actualTrigger.getParam("Execute")); - SpellAbility sa = AbilityFactory.getAbility(svar, hostCard); - // set hostcard there so when the card is added to trigger, it doesn't make a copy of it - sa.setHostCard(affectedCard); - // set OriginalHost to get the owner of this static ability - sa.setOriginalHost(hostCard); // set overriding ability to the trigger - actualTrigger.setOverridingAbility(sa); + actualTrigger.setOverridingAbility(AbilityFactory.getAbility(affectedCard, actualTrigger.getParam("Execute"), stAb)); } + actualTrigger.setOriginalHost(hostCard); actualTrigger.setIntrinsic(false); addedTrigger.add(actualTrigger); } @@ -814,6 +809,7 @@ public final class StaticAbilityContinuous { StaticAbility stat = new StaticAbility(s, affectedCard); stat.setIntrinsic(false); + stat.setOriginalHost(hostCard); addedStaticAbility.add(stat); } } diff --git a/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java b/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java index 9277b987af0..92083daab65 100644 --- a/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java +++ b/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java @@ -14,7 +14,6 @@ import forge.game.spellability.*; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; @@ -314,11 +313,6 @@ public class WrappedAbility extends Ability { return sa.isXCost(); } - @Override - public String getSvarWithFallback(String name) { - return sa.getSvarWithFallback(name); - } - @Override public String getSVar(String name) { return sa.getSVar(name); @@ -330,7 +324,7 @@ public class WrappedAbility extends Ability { } @Override - public Set getSVars() { + public Map getSVars() { return sa.getSVars(); } diff --git a/forge-gui/res/cardsfolder/upcoming/kaya_the_inexorable.txt b/forge-gui/res/cardsfolder/upcoming/kaya_the_inexorable.txt new file mode 100644 index 00000000000..2691465d73b --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/kaya_the_inexorable.txt @@ -0,0 +1,17 @@ +Name:Kaya the Inexorable +ManaCost:3 W B +Types:Legendary Planeswalker Kaya +Loyalty:5 +A:AB$ PutCounter | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | ValidTgts$ Creature.nonToken | AITgts$ Creature.nonToken+YouCtrl | TgtPrompt$ Select target nontoken creature | TargetMin$ 0 | TargetMax$ 1 | CounterType$ GHOSTFORM | CounterNum$ 1 | SubAbility$ DBAnimate | SpellDescription$ Put a ghostform counter on up to one target nontoken creature. It gains "When this creature dies or is put into exile, return it to its owner's hand and create a 1/1 white Spirit creature token with flying." +SVar:DBAnimate:DB$ Animate | Defined$ Targeted | Permanent$ True | Triggers$ TrigDieExile | StackDescription$ {c:Targeted} gains "When this creature dies or is put into exile, return it to its owner's hand and create a 1/1 white Spirit creature token with flying." +SVar:TrigDieExile:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard,Exile | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When this creature dies or is put into exile, return it to its owner's hand and create a 1/1 white Spirit creature token with flying. +SVar:TrigReturn:DB$ ChangeZone | Defined$ TriggeredNewCardLKICopy | Origin$ All | Destination$ Hand | SubAbility$ DBToken +SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_1_1_spirit_flying | TokenOwner$ TriggeredCardController +A:AB$ ChangeZone | Cost$ SubCounter<3/LOYALTY> | Planeswalker$ True | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | SpellDescription$ Exile target nonland permanent. +A:AB$ Effect | Cost$ SubCounter<7/LOYALTY> | Planeswalker$ True | Ultimate$ True | Name$ Emblem - Kaya the Inexorable | Image$ emblem_kaya_the_inexorable | Duration$ Permanent | Triggers$ Upkeep | SpellDescription$ You get an emblem with "At the beginning of your upkeep, you may cast a legendary spell from your hand, from your graveyard, or from among cards you own in exile without paying its mana cost." +SVar:Upkeep:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Command | OptionalDecider$ You | Execute$ TrigCast | TriggerDescription$ At the beginning of your upkeep, you may cast a legendary spell from your hand, from your graveyard, or from among cards you own in exile without paying its mana cost. +SVar:TrigCast:DB$ Play | Valid$ Card.Legendary+YouOwn | ValidZone$ Hand,Graveyard,Exile | WithoutManaCost$ True +DeckHas:Ability$Token & Ability$Counters +DeckHints:Type$Legendary +Oracle:[+1]: Put a ghostform counter on up to one target nontoken creature. It gains "When this creature dies or is put into exile, return it to its owner's hand and create a 1/1 white Spirit creature token with flying."\n[−3]: Exile target nonland permanent.\n[−7]: You get an emblem with "At the beginning of your upkeep, you may cast a legendary spell from your hand, from your graveyard, or from among cards you own in exile without paying its mana cost." + From e801ff94e50da19952741970ff9251f4df0d81a8 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Sat, 19 Dec 2020 08:50:21 +0100 Subject: [PATCH 47/97] AnimateAi: fix mandatory needs to use getTargetableCards --- .../main/java/forge/ai/ability/AnimateAi.java | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java b/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java index 95d1835c9a6..7fcc06b0507 100644 --- a/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java @@ -14,7 +14,6 @@ import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.game.staticability.StaticAbility; import forge.game.staticability.StaticAbilityContinuous; import forge.game.staticability.StaticAbilityLayer; @@ -38,15 +37,13 @@ import forge.game.ability.effects.AnimateEffectBase; public class AnimateAi extends SpellAbilityAi { @Override protected boolean checkAiLogic(final Player ai, final SpellAbility sa, final String aiLogic) { - final TargetRestrictions tgt = sa.getTargetRestrictions(); - final Card source = sa.getHostCard(); final Game game = ai.getGame(); final PhaseHandler ph = game.getPhaseHandler(); if ("Attacking".equals(aiLogic)) { // Launch the Fleet if (ph.getPlayerTurn().isOpponentOf(ai) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)) { return false; } - List list = CardLists.getValidCards(ai.getCreaturesInPlay(), tgt.getValidTgts(), ai, source, sa); + List list = CardLists.getTargetableCards(ai.getCreaturesInPlay(), sa); for (Card c : list) { if (ComputerUtilCard.doesCreatureAttackAI(ai, c)) { sa.getTargets().add(c); @@ -224,10 +221,7 @@ public class AnimateAi extends SpellAbilityAi { } else if (sa.usesTargeting() && mandatory) { // fallback if animate is mandatory sa.resetTargets(); - final TargetRestrictions tgt = sa.getTargetRestrictions(); - final Card source = sa.getHostCard(); - CardCollectionView list = aiPlayer.getGame().getCardsIn(tgt.getZone()); - list = CardLists.getValidCards(list, tgt.getValidTgts(), aiPlayer, source, sa); + List list = CardUtil.getValidCardsToTarget(sa.getTargetRestrictions(), sa); if (list.isEmpty()) { return false; } @@ -253,12 +247,8 @@ public class AnimateAi extends SpellAbilityAi { // something is used for animate into creature if (types.isCreature()) { - final TargetRestrictions tgt = sa.getTargetRestrictions(); - final Card source = sa.getHostCard(); - CardCollectionView list = ai.getGame().getCardsIn(tgt.getZone()); - list = CardLists.getValidCards(list, tgt.getValidTgts(), ai, source, sa); - // need to targetable - list = CardLists.getTargetableCards(list, sa); + final Game game = ai.getGame(); + CardCollectionView list = CardLists.getTargetableCards(game.getCardsIn(ZoneType.Battlefield), sa); // Filter AI-specific targets if provided list = ComputerUtil.filterAITgts(sa, ai, (CardCollection)list, false); From a321e515830e9bdc6076c52c25c18104e296e318 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Sat, 19 Dec 2020 12:35:58 +0100 Subject: [PATCH 48/97] MDFC: fix SpellPerm for Kaldheim --- .../effects/PermanentNoncreatureEffect.java | 2 +- .../src/main/java/forge/game/card/Card.java | 19 +++++++++++++-- .../java/forge/game/card/CardFactory.java | 11 +++++++-- .../forge/game/spellability/SpellAbility.java | 2 +- ...lvar_god_of_battle_sword_of_the_realms.txt | 23 +++++++++++++++++++ 5 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 forge-gui/res/cardsfolder/upcoming/halvar_god_of_battle_sword_of_the_realms.txt diff --git a/forge-game/src/main/java/forge/game/ability/effects/PermanentNoncreatureEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PermanentNoncreatureEffect.java index 6295abb75b5..c5e8fa78f8b 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PermanentNoncreatureEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PermanentNoncreatureEffect.java @@ -13,6 +13,6 @@ public class PermanentNoncreatureEffect extends PermanentEffect { public String getStackDescription(final SpellAbility sa) { final Card sourceCard = sa.getHostCard(); //CardView toString return translated name,don't need call CardTranslation.getTranslatedName in this. - return sourceCard.toString(); + return sourceCard.getName(); } } diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index a5180904bfb..e8a485543e9 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -6035,6 +6035,17 @@ public class Card extends GameEntity implements Comparable, IHasSVars { abilities.addAll(GameActionUtil.getAlternativeCosts(sa, player)); } } + // Add Modal Spells + if (isModal() && hasState(CardStateName.Modal)) { + for (SpellAbility sa : getState(CardStateName.Modal).getSpellAbilities()) { + //add alternative costs as additional spell abilities + // only add Spells there + if (sa.isSpell()) { + abilities.add(sa); + abilities.addAll(GameActionUtil.getAlternativeCosts(sa, player)); + } + } + } final Collection toRemove = Lists.newArrayListWithCapacity(abilities.size()); for (final SpellAbility sa : abilities) { @@ -6050,7 +6061,11 @@ public class Card extends GameEntity implements Comparable, IHasSVars { } abilities.removeAll(toRemove); - if (getState(CardStateName.Original).getType().isLand() && !getLastKnownZone().is(ZoneType.Battlefield)) { + // Land Abilities below, move them to CardFactory after MayPlayRefactor + if (getLastKnownZone().is(ZoneType.Battlefield)) { + return abilities; + } + if (getState(CardStateName.Original).getType().isLand()) { LandAbility la = new LandAbility(this, player, null); if (la.canPlay()) { abilities.add(la); @@ -6092,7 +6107,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { } if (isModal() && hasState(CardStateName.Modal)) { - if (getState(CardStateName.Modal).getType().isLand() && !getLastKnownZone().is(ZoneType.Battlefield)) { + if (getState(CardStateName.Modal).getType().isLand()) { LandAbility la = new LandAbility(this, player, null); la.setCardState(CardStateName.Modal); diff --git a/forge-game/src/main/java/forge/game/card/CardFactory.java b/forge-game/src/main/java/forge/game/card/CardFactory.java index d8e0c191986..5dbfabc2740 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactory.java +++ b/forge-game/src/main/java/forge/game/card/CardFactory.java @@ -392,11 +392,18 @@ public class CardFactory { } // SpellPermanent only for Original State - if (c.getCurrentStateName() == CardStateName.Original) { + if (c.getCurrentStateName() == CardStateName.Original || c.getCurrentStateName() == CardStateName.Modal) { // this is the "default" spell for permanents like creatures and artifacts if (c.isPermanent() && !c.isAura() && !c.isLand()) { - c.addSpellAbility(new SpellPermanent(c)); + SpellAbility sa = new SpellPermanent(c); + + // Currently only for Modal, might react different when state is always set + if (c.getCurrentStateName() == CardStateName.Modal) { + sa.setCardState(c.getCurrentStateName()); + } + c.addSpellAbility(sa); } + // TODO add LandAbility there when refactor MayPlay } CardFactoryUtil.addAbilityFactoryAbilities(c, face.getAbilities()); diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java index 227a81902ee..8a2b50d9bfa 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -620,7 +620,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit public String getStackDescription() { String text = getHostCard().getView().getText(); - if (stackDescription.equals(text)) { + if (stackDescription.equals(text) && !text.isEmpty()) { return getHostCard().getName() + " - " + text; } return TextUtil.fastReplace(stackDescription, "CARDNAME", getHostCard().getName()); diff --git a/forge-gui/res/cardsfolder/upcoming/halvar_god_of_battle_sword_of_the_realms.txt b/forge-gui/res/cardsfolder/upcoming/halvar_god_of_battle_sword_of_the_realms.txt new file mode 100644 index 00000000000..d0c52a48069 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/halvar_god_of_battle_sword_of_the_realms.txt @@ -0,0 +1,23 @@ +Name:Halvar, God of Battle +ManaCost:2 W W +Types:Legendary Creature God +PT:4/4 +S:Mode$ Continuous | Affected$ Creature.YouCtrl+enchanted,Creature.YouCtrl+equipped | AddKeyword$ Double Strike | Description$ Creatures you control that are enchanted or equipped gain double strike. +T:Mode$ Phase | Phase$ BeginCombat | TriggerZones$ Battlefield | Execute$ TrigTargetAuraEquip | OptionalDecider$ You | TriggerDescription$ At the beginning of each combat, you may attach target Aura or Equipment attached to a creature you control to target creature you control. +SVar:TrigTargetAuraEquip:DB$ Pump | ValidTgts$ Equipment.AttachedTo Creature.YouCtrl,Aura.AttachedTo Creature.YouCtrl | TgtPrompt$ Select target Aura or Equipment attached to a creature you control | SubAbility$ DBAttach | StackDescription$ None +SVar:DBAttach:DB$ Attach | Object$ ParentTarget | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control +AlternateMode:Modal +DeckHints:Type$Equipment|Aura +Oracle:Creatures you control that are enchanted or equipped have double strike.\nAt the beginning of each combat, you may attach target Aura or Equipment attached to a creature you control to target creature you control. + +ALTERNATE + +Name:Sword of the Realms +ManaCost:1 W +Types:Legendary Artifact Equipment +K:Equip:1 W +S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 2 | AddKeyword$ Vigilance | Description$ Equipped creature gets +2/+0 and has vigilance. +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.AttachedBy | Execute$ TrigReturn | TriggerDescription$ Whenever equipped creature dies, return it to its owner's hand. +SVar:TrigReturn:DB$ ChangeZone | Defined$ TriggeredNewCardLKICopy | Origin$ Graveyard | Destination$ Hand +Oracle:Equipped creature gets +2/+0 and has vigilance.\nWhenever equipped creature dies, return it to its owner's hand.\nEquip {1} {W} + From 0d5b1ee3244fe6eee69b3f898b499836edbbe6d5 Mon Sep 17 00:00:00 2001 From: Tim Mocny Date: Sun, 20 Dec 2020 07:04:51 +0000 Subject: [PATCH 49/97] Fixes --- forge-gui/res/cardsfolder/n/necropotence.txt | 3 ++- forge-gui/res/cardsfolder/p/portcullis.txt | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/forge-gui/res/cardsfolder/n/necropotence.txt b/forge-gui/res/cardsfolder/n/necropotence.txt index faed1082aa5..e22a9175061 100644 --- a/forge-gui/res/cardsfolder/n/necropotence.txt +++ b/forge-gui/res/cardsfolder/n/necropotence.txt @@ -3,7 +3,7 @@ ManaCost:B B B Types:Enchantment S:Mode$ Continuous | Affected$ You | AddKeyword$ Skip your draw step. | Description$ Skip your draw step. T:Mode$ Discarded | ValidCard$ Card.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigChange | TriggerDescription$ Whenever you discard a card, exile that card from your graveyard. -SVar:TrigChange:DB$ ChangeZone | Defined$ TriggeredCardLKICopy | Origin$ Graveyard | Destination$ Exile +SVar:TrigChange:DB$ ChangeZone | Defined$ TriggeredCard | Origin$ Graveyard | Destination$ Exile A:AB$ ChangeZone | Cost$ PayLife<1> | Defined$ TopOfLibrary | Origin$ Library | Destination$ Exile | ExileFaceDown$ True | RememberChanged$ True | SubAbility$ DelayedReturn | AILogic$ Necropotence | AILifeThreshold$ 1 | SpellDescription$ Exile the top card of your library face down. Put that card into your hand at the beginning of your next end step. SVar:DelayedReturn:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | Execute$ TrigReturn | RememberObjects$ RememberedLKI | TriggerDescription$ Put the exiled card into your hand. | SubAbility$ DBCleanup SVar:TrigReturn:DB$ ChangeZone | Origin$ Exile | Destination$ Hand | Defined$ DelayTriggerRememberedLKI @@ -11,4 +11,5 @@ SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:AICastPreference:NeverCastIfLifeBelow$ 7 AI:RemoveDeck:Random SVar:NonStackingEffect:True +DeckHints:Ability$LifeGain Oracle:Skip your draw step.\nWhenever you discard a card, exile that card from your graveyard.\nPay 1 life: Exile the top card of your library face down. Put that card into your hand at the beginning of your next end step. diff --git a/forge-gui/res/cardsfolder/p/portcullis.txt b/forge-gui/res/cardsfolder/p/portcullis.txt index 51730619950..82ff88ef890 100644 --- a/forge-gui/res/cardsfolder/p/portcullis.txt +++ b/forge-gui/res/cardsfolder/p/portcullis.txt @@ -2,8 +2,8 @@ Name:Portcullis ManaCost:4 Types:Artifact T:Mode$ ChangesZone | ValidCard$ Creature | Origin$ Any | Destination$ Battlefield | Execute$ TrigExile | TriggerZones$ Battlefield | TriggerDescription$ Whenever a creature enters the battlefield, if there are two or more other creatures on the battlefield, exile that creature. -T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Battlefield | Destination$ Any | Execute$ TrigReturn | TriggerController$ TriggeredCardController | TriggerDescription$ Return that card to the battlefield under its owner's control when CARDNAME leaves the battlefield. -SVar:TrigExile:DB$ ChangeZone | ConditionPresent$ Creature | ConditionCompare$ GE3 | Defined$ TriggeredNewCardLKICopy | RememberChanged$ True | Origin$ Battlefield | Destination$ Exile +SVar:TrigExile:DB$ ChangeZone | ConditionPresent$ Creature | ConditionCompare$ GE3 | Defined$ TriggeredCard | RememberChanged$ True | Origin$ Battlefield | Destination$ Exile +T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Battlefield | Destination$ Any | Execute$ TrigReturn | TriggerDescription$ Return that card to the battlefield under its owner's control when CARDNAME leaves the battlefield. SVar:TrigReturn:DB$ ChangeZoneAll | ChangeType$ Card.IsRemembered | Origin$ Exile | Destination$ Battlefield | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True AI:RemoveDeck:Random From f670e131f91e9cf2e3ba72ee762f3a4e66e9d59f Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Sun, 20 Dec 2020 08:40:16 +0000 Subject: [PATCH 50/97] Resolve "Use hash set instead of enum set for Keyword sets" --- .../src/main/java/forge/game/card/Card.java | 3 +- .../forge/game/keyword/KeywordCollection.java | 55 ++++++++----------- .../main/java/forge/game/player/Player.java | 5 +- .../java/forge/game/player/PlayerView.java | 2 +- 4 files changed, 30 insertions(+), 35 deletions(-) diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index e8a485543e9..81e44e01124 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -124,7 +124,8 @@ public class Card extends GameEntity implements Comparable, IHasSVars { private final PlayerCollection mayLookFaceDownExile = new PlayerCollection(); private final PlayerCollection mayLookTemp = new PlayerCollection(); - private final Multimap cantHaveKeywords = MultimapBuilder.hashKeys().enumSetValues(Keyword.class).build(); + // don't use Enum Set Values or it causes a slow down + private final Multimap cantHaveKeywords = MultimapBuilder.hashKeys().hashSetValues().build(); private final Map counterTypeTimestamps = Maps.newHashMap(); diff --git a/forge-game/src/main/java/forge/game/keyword/KeywordCollection.java b/forge-game/src/main/java/forge/game/keyword/KeywordCollection.java index de9f14c2ecf..56a10e903c1 100644 --- a/forge-game/src/main/java/forge/game/keyword/KeywordCollection.java +++ b/forge-game/src/main/java/forge/game/keyword/KeywordCollection.java @@ -1,22 +1,22 @@ package forge.game.keyword; -import java.io.Serializable; - import java.util.Collection; import java.util.Iterator; +import java.util.List; +import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.collect.MultimapBuilder; import forge.game.card.Card; -public class KeywordCollection implements Iterable, Serializable { - private static final long serialVersionUID = -2882986558147844702L; +public class KeywordCollection implements Iterable { private boolean hidden = false; private transient KeywordCollectionView view; - private final Multimap map = MultimapBuilder.enumKeys(Keyword.class) + // don't use enumKeys it causes a slow down + private final Multimap map = MultimapBuilder.hashKeys() .arrayListValues().build(); public KeywordCollection() { @@ -157,35 +157,20 @@ public class KeywordCollection implements Iterable, Serializable { return map.get(keyword); } + public List asStringList() { + List result = Lists.newArrayList(); + for (KeywordInterface kw : getValues()) { + result.add(kw.getOriginal()); + } + return result; + } + public void setHostCard(final Card host) { for (KeywordInterface k : map.values()) { k.setHostCard(host); } } - @Override - public Iterator iterator() { - return new Iterator() { - private final Iterator iterator = map.values().iterator(); - - @Override - public boolean hasNext() { - return iterator.hasNext(); - } - - @Override - public String next() { - KeywordInterface entry = iterator.next(); - return entry.getOriginal(); - } - - @Override - public void remove() { - //Don't support this - } - }; - } - /* (non-Javadoc) * @see java.lang.Object#toString() */ @@ -204,8 +189,7 @@ public class KeywordCollection implements Iterable, Serializable { return view; } - public class KeywordCollectionView implements Iterable, Serializable { - private static final long serialVersionUID = 7536969077044188264L; + public class KeywordCollectionView implements Iterable { protected KeywordCollectionView() { } @@ -229,9 +213,18 @@ public class KeywordCollection implements Iterable, Serializable { return KeywordCollection.this.contains(keyword); } + public List asStringList() { + return KeywordCollection.this.asStringList(); + } + @Override - public Iterator iterator() { + public Iterator iterator() { return KeywordCollection.this.iterator(); } } + + @Override + public Iterator iterator() { + return this.map.values().iterator(); + } } diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index e24173bef9e..3cf09db7d1f 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -1236,7 +1236,8 @@ public class Player extends GameEntity implements Comparable { public boolean hasProtectionFrom(final Card source, final boolean checkSBA, final boolean damageSource) { final boolean colorlessDamage = damageSource && source.hasKeyword("Colorless Damage Source"); - for (String kw : keywords) { + for (KeywordInterface ki : keywords) { + String kw = ki.getOriginal(); if (kw.startsWith("Protection")) { if (kw.startsWith("Protection:")) { // uses isValid final String characteristic = kw.split(":")[1]; @@ -3226,7 +3227,7 @@ public class Player extends GameEntity implements Comparable { keywordEffect.updateAbilityTextForView(); boolean headerAdded = false; StringBuilder kw = new StringBuilder(); - for(String k : keywords) { + for(KeywordInterface k : keywords) { if(!headerAdded) { headerAdded = true; kw.append(this.getName()).append(" has: \n"); diff --git a/forge-game/src/main/java/forge/game/player/PlayerView.java b/forge-game/src/main/java/forge/game/player/PlayerView.java index 311177cdc3e..19e6e1cb6fd 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerView.java +++ b/forge-game/src/main/java/forge/game/player/PlayerView.java @@ -311,7 +311,7 @@ public class PlayerView extends GameEntityView { return getKeywords().contains(keyword); } void updateKeywords(Player p) { - set(TrackableProperty.Keywords, ImmutableMultiset.copyOf(p.getKeywords())); + set(TrackableProperty.Keywords, ImmutableMultiset.copyOf(p.getKeywords().asStringList())); } public List getCommanders() { From 0d701224bf37131ecc5bdb2e9627f4018b9020e2 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Sun, 20 Dec 2020 10:41:40 +0100 Subject: [PATCH 51/97] Player: fix KeywordCollection iterating KeywordInterfaces --- .../forge/game/ability/effects/FlipCoinEffect.java | 9 ++------- .../main/java/forge/game/card/CardFactoryUtil.java | 11 +++-------- forge-game/src/main/java/forge/game/phase/Untap.java | 4 +++- .../game/staticability/StaticAbilityCantTarget.java | 10 +++++++--- 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/forge-game/src/main/java/forge/game/ability/effects/FlipCoinEffect.java b/forge-game/src/main/java/forge/game/ability/effects/FlipCoinEffect.java index e16f59a92c5..b8e20cb1ba5 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/FlipCoinEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/FlipCoinEffect.java @@ -224,12 +224,7 @@ public class FlipCoinEffect extends SpellAbilityEffect { } public static int getFilpMultiplier(final Player flipper) { - int i = 0; - for (String kw : flipper.getKeywords()) { - if (kw.startsWith("If you would flip a coin")) { - i++; - } - } - return 1 << i; + String str = "If you would flip a coin, instead flip two coins and ignore one."; + return 1 + flipper.getKeywords().getAmount(str); } } diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java index 255fdd911dd..6fbb9498557 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -1176,14 +1176,9 @@ public class CardFactoryUtil { return doXMath(Integer.parseInt(sq[cc.hasThreshold() ? 1 : 2]), m, c); } if (sq[0].contains("Averna")) { - int kwcount = 0; - for (String kw : cc.getKeywords()) { - if (kw.equals("As you cascade, you may put a land card from among the exiled cards onto the " + - "battlefield tapped.")) { - kwcount++; - } - } - return kwcount; + String str = "As you cascade, you may put a land card from among the exiled cards onto the " + + "battlefield tapped."; + return cc.getKeywords().getAmount(str); } if (sq[0].startsWith("Kicked")) { return doXMath(Integer.parseInt(sq[c.getKickerMagnitude() > 0 ? 1 : 2]), m, c); diff --git a/forge-game/src/main/java/forge/game/phase/Untap.java b/forge-game/src/main/java/forge/game/phase/Untap.java index 6fe6668b151..94fb0f26773 100644 --- a/forge-game/src/main/java/forge/game/phase/Untap.java +++ b/forge-game/src/main/java/forge/game/phase/Untap.java @@ -29,6 +29,7 @@ import forge.game.card.CardCollection; import forge.game.card.CardLists; import forge.game.card.CardPredicates.Presets; import forge.game.keyword.Keyword; +import forge.game.keyword.KeywordInterface; import forge.game.player.Player; import forge.game.player.PlayerController.BinaryChoiceType; import forge.game.spellability.SpellAbility; @@ -125,7 +126,8 @@ public class Untap extends Phase { final Map restrictUntap = Maps.newHashMap(); boolean hasChosen = false; - for (String kw : player.getKeywords()) { + for (KeywordInterface ki : player.getKeywords()) { + String kw = ki.getOriginal(); if (kw.startsWith("UntapAdjust")) { String[] parse = kw.split(":"); if (!restrictUntap.containsKey(parse[1]) diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantTarget.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantTarget.java index 00243f7e4c9..656749c5285 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantTarget.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantTarget.java @@ -18,6 +18,7 @@ package forge.game.staticability; import forge.game.card.Card; +import forge.game.keyword.KeywordInterface; import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; @@ -74,7 +75,8 @@ public class StaticAbilityCantTarget { if (st.hasParam("Hexproof") && (activator != null)) { - for (String k : activator.getKeywords()) { + for (KeywordInterface kw : activator.getKeywords()) { + String k = kw.getOriginal(); if (k.startsWith("IgnoreHexproof")) { String[] m = k.split(":"); if (card.isValid(m[1].split(","), activator, source, spellAbility)) { @@ -84,7 +86,8 @@ public class StaticAbilityCantTarget { } } if (st.hasParam("Shroud") && (activator != null)) { - for (String k : activator.getKeywords()) { + for (KeywordInterface kw : activator.getKeywords()) { + String k = kw.getOriginal(); if (k.startsWith("IgnoreShroud")) { String[] m = k.split(":"); if (card.isValid(m[1].split(","), activator, source, spellAbility)) { @@ -114,7 +117,8 @@ public class StaticAbilityCantTarget { if (st.hasParam("Hexproof") && (activator != null)) { - for (String k : activator.getKeywords()) { + for (KeywordInterface kw : activator.getKeywords()) { + String k = kw.getOriginal(); if (k.startsWith("IgnoreHexproof")) { String[] m = k.split(":"); if (player.isValid(m[1].split(","), activator, source, spellAbility)) { From 54c8fd74eb29c9d0d954a63ac927c1a92769cdfc Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Sun, 20 Dec 2020 11:10:41 +0100 Subject: [PATCH 52/97] SpellAbility: remove totalManaSpent variable --- .../main/java/forge/game/spellability/SpellAbility.java | 8 +------- forge-game/src/main/java/forge/game/zone/MagicStack.java | 5 ----- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java index 8a2b50d9bfa..56f438b75b2 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -114,8 +114,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit private CardStateName stateName = null; - private int totalManaSpent = 0; - /** The pay costs. */ private Cost payCosts; private SpellAbilityRestriction restrictions = new SpellAbilityRestriction(); @@ -1785,12 +1783,8 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit } } - public void setTotalManaSpent(int totManaSpent) { - totalManaSpent = totManaSpent; - } - public int getTotalManaSpent() { - return totalManaSpent; + return this.getPayingMana().size(); } public List getChosenList() { diff --git a/forge-game/src/main/java/forge/game/zone/MagicStack.java b/forge-game/src/main/java/forge/game/zone/MagicStack.java index ba22a8349e7..19e2ad0465d 100644 --- a/forge-game/src/main/java/forge/game/zone/MagicStack.java +++ b/forge-game/src/main/java/forge/game/zone/MagicStack.java @@ -273,11 +273,8 @@ public class MagicStack /* extends MyObservable */ implements Iterable runParams = AbilityKey.newMap(); if (!sp.isCopied()) { From c1cdcdcdfb17e2a99b7efd98ba4be0247e2a7da2 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Tue, 22 Dec 2020 00:00:17 +0800 Subject: [PATCH 53/97] -[Android] Option for Auto Cache size --- forge-gui-mobile/src/forge/Forge.java | 16 +++++++++---- .../forge/itemmanager/views/ImageView.java | 4 +++- .../forge/screens/settings/SettingsPage.java | 23 +++++++++++++++++++ forge-gui/res/languages/de-DE.properties | 2 ++ forge-gui/res/languages/en-US.properties | 2 ++ forge-gui/res/languages/es-ES.properties | 2 ++ forge-gui/res/languages/it-IT.properties | 2 ++ forge-gui/res/languages/zh-CN.properties | 2 ++ .../forge/properties/ForgePreferences.java | 1 + 9 files changed, 48 insertions(+), 6 deletions(-) diff --git a/forge-gui-mobile/src/forge/Forge.java b/forge-gui-mobile/src/forge/Forge.java index 7870c987f29..4dd2ed5771d 100644 --- a/forge-gui-mobile/src/forge/Forge.java +++ b/forge-gui-mobile/src/forge/Forge.java @@ -76,6 +76,7 @@ public class Forge implements ApplicationListener { public static int cacheSize = 400; public static int totalDeviceRAM = 0; public static int androidVersion = 0; + public static boolean autoCache = false; public static ApplicationListener getApp(Clipboard clipboard0, IDeviceAdapter deviceAdapter0, String assetDir0, boolean value, boolean androidOrientation, int totalRAM, boolean isTablet, int AndroidVersion) { if (GuiBase.getInterface() == null) { @@ -87,9 +88,6 @@ public class Forge implements ApplicationListener { totalDeviceRAM = totalRAM; isTabletDevice = isTablet; androidVersion = AndroidVersion; - //increase cacheSize for devices with RAM more than 5GB, default is 400. Some phones have more than 10GB RAM (Mi 10, OnePlus 8, S20, etc..) - if (totalDeviceRAM>5000) //devices with more than 10GB RAM will have 1000 Cache size, 700 Cache size for morethan 5GB RAM - cacheSize = totalDeviceRAM>10000 ? 1000: 700; } return app; } @@ -103,6 +101,7 @@ public class Forge implements ApplicationListener { ExceptionHandler.registerErrorHandling(); GuiBase.setIsAndroid(Gdx.app.getType() == Application.ApplicationType.Android); + graphics = new Graphics(); splashScreen = new SplashScreen(); frameRate = new FrameRate(); @@ -132,6 +131,13 @@ public class Forge implements ApplicationListener { enableUIMask = prefs.getPrefBoolean(FPref.UI_ENABLE_BORDER_MASKING); enablePreloadExtendedArt = prefs.getPrefBoolean(FPref.UI_ENABLE_PRELOAD_EXTENDED_ART); locale = prefs.getPref(FPref.UI_LANGUAGE); + autoCache = prefs.getPrefBoolean(FPref.UI_AUTO_CACHE_SIZE); + + if (autoCache) { + //increase cacheSize for devices with RAM more than 5GB, default is 400. Some phones have more than 10GB RAM (Mi 10, OnePlus 8, S20, etc..) + if (totalDeviceRAM>5000) //devices with more than 10GB RAM will have 1000 Cache size, 700 Cache size for morethan 5GB RAM + cacheSize = totalDeviceRAM>10000 ? 1000: 700; + } final Localizer localizer = Localizer.getInstance(); @@ -155,12 +161,12 @@ public class Forge implements ApplicationListener { //add reminder to preload if (enablePreloadExtendedArt) { - if(totalDeviceRAM>0) + if(autoCache) splashScreen.getProgressBar().setDescription(localizer.getMessage("lblPreloadExtendedArt")+"\nDetected RAM: " +totalDeviceRAM+"MB. Cache size: "+cacheSize); else splashScreen.getProgressBar().setDescription(localizer.getMessage("lblPreloadExtendedArt")); } else { - if(totalDeviceRAM>0) + if(autoCache) splashScreen.getProgressBar().setDescription(localizer.getMessage("lblFinishingStartup")+"\nDetected RAM: " +totalDeviceRAM+"MB. Cache size: "+cacheSize); else splashScreen.getProgressBar().setDescription(localizer.getMessage("lblFinishingStartup")); diff --git a/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java b/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java index 8456a248ad4..46a5d810514 100644 --- a/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java +++ b/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java @@ -1023,7 +1023,9 @@ public class ImageView extends ItemView { g.drawText(item.getName(), GROUP_HEADER_FONT, Color.WHITE, x + PADDING, y + PADDING*2, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, false); } else { if (!dp.isGeneratedDeck()){ - FImageComplex cardArt = CardRenderer.getCardArt(dp.getHighestCMCCard().getImageKey(false), false, false, false); + //If deck has Commander, use it as cardArt reference + String deckImageKey = dp.getDeck().getCommanders().isEmpty() ? dp.getHighestCMCCard().getImageKey(false) : dp.getDeck().getCommanders().get(0).getImageKey(false); + FImageComplex cardArt = CardRenderer.getCardArt(deckImageKey, false, false, false); //draw the deckbox if (cardArt == null){ //draw generic box if null or still loading diff --git a/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java b/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java index c55b92edbba..f2f0f34708e 100644 --- a/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java +++ b/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java @@ -274,6 +274,29 @@ public class SettingsPage extends TabPage { } }, 3); + if (GuiBase.isAndroid()) { //this option does nothing except on Android + lstSettings.addItem(new BooleanSetting(FPref.UI_AUTO_CACHE_SIZE, + localizer.getMessage("lblAutoCacheSize"), + localizer.getMessage("nlAutoCacheSize")) { + @Override + public void select() { + super.select(); + FOptionPane.showConfirmDialog( + localizer.getMessage("lblRestartForgeDescription"), + localizer.getMessage("lblRestartForge"), + localizer.getMessage("lblRestart"), + localizer.getMessage("lblLater"), new Callback() { + @Override + public void run(Boolean result) { + if (result) { + Forge.restart(true); + } + } + }); + } + }, + 3); + } //Graphic Options lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_ONLINE_IMAGE_FETCHER, diff --git a/forge-gui/res/languages/de-DE.properties b/forge-gui/res/languages/de-DE.properties index 850991e95a7..d0ca05955e3 100644 --- a/forge-gui/res/languages/de-DE.properties +++ b/forge-gui/res/languages/de-DE.properties @@ -994,6 +994,8 @@ lblEnableUnknownCards=Erlaube unbekannte Karten nlEnableUnknownCards=Erlaube unbekannte Karten von unbekannten Sets. (Erfordert Neustart) lblExperimentalNetworkCompatibility=Experimentelle Netzwerkkompatibilität nlExperimentalNetworkCompatibility=Forge wechselt auf kompatiblen Netzwerk-Stream. (Im Zweifel bitte ausschalten) +lblAutoCacheSize=Enable Auto Cache Size +nlAutoCacheSize=When enabled, Cache size are automatically determined on startup. (If unsure, turn OFF this option) #MatchScreen.java lblPlayers=Spieler lblLog=Bericht diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index b84f92620de..c4cca0dd335 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -994,6 +994,8 @@ lblEnableUnknownCards=Enable Unknown Cards nlEnableUnknownCards=Enable Unknown Cards to be loaded to Unknown Set. (Requires restart) lblExperimentalNetworkCompatibility=Experimental Network Compatibility nlExperimentalNetworkCompatibility=Forge switches to compatible network stream. (If unsure, turn OFF this option) +lblAutoCacheSize=Enable Auto Cache Size +nlAutoCacheSize=When enabled, Cache size are automatically determined on startup. (If unsure, turn OFF this option) #MatchScreen.java lblPlayers=Players lblLog=Log diff --git a/forge-gui/res/languages/es-ES.properties b/forge-gui/res/languages/es-ES.properties index b216379240a..adf0243c33e 100644 --- a/forge-gui/res/languages/es-ES.properties +++ b/forge-gui/res/languages/es-ES.properties @@ -994,6 +994,8 @@ lblEnableUnknownCards=Habilitar Cartas Desconocidas nlEnableUnknownCards=Habilitar que las cartas desconocidas se carguen en el Unknown Set. (Requiere reinicio) lblExperimentalNetworkCompatibility=Compatibilidad de red experimental nlExperimentalNetworkCompatibility=Forge cambia a un flujo de red compatible. (Si no estás seguro, deshabilita esta opción) +lblAutoCacheSize=Enable Auto Cache Size +nlAutoCacheSize=When enabled, Cache size are automatically determined on startup. (If unsure, turn OFF this option) #MatchScreen.java lblPlayers=Jugadores lblLog=Log diff --git a/forge-gui/res/languages/it-IT.properties b/forge-gui/res/languages/it-IT.properties index 239f63a061e..f4476649095 100644 --- a/forge-gui/res/languages/it-IT.properties +++ b/forge-gui/res/languages/it-IT.properties @@ -994,6 +994,8 @@ lblEnableUnknownCards=Enable Unknown Cards nlEnableUnknownCards=Enable Unknown Cards to be loaded to Unknown Set. (Requires restart) lblExperimentalNetworkCompatibility=Experimental Network Compatibility nlExperimentalNetworkCompatibility=Forge switches to compatible network stream. (If unsure, turn OFF this option) +lblAutoCacheSize=Enable Auto Cache Size +nlAutoCacheSize=When enabled, Cache size are automatically determined on startup. (If unsure, turn OFF this option) #MatchScreen.java lblPlayers=Giocatori lblLog=Login diff --git a/forge-gui/res/languages/zh-CN.properties b/forge-gui/res/languages/zh-CN.properties index c6dc2843020..020724d593a 100644 --- a/forge-gui/res/languages/zh-CN.properties +++ b/forge-gui/res/languages/zh-CN.properties @@ -994,6 +994,8 @@ lblEnableUnknownCards=启用未知卡牌 nlEnableUnknownCards=将未知卡牌加载到未知系列中。(需要重启) lblExperimentalNetworkCompatibility=实验性网络兼容 nlExperimentalNetworkCompatibility=Forge将切换为兼容性的网络流。(如果不清楚,请关闭此选项) +lblAutoCacheSize=Enable Auto Cache Size +nlAutoCacheSize=When enabled, Cache size are automatically determined on startup. (If unsure, turn OFF this option) #MatchScreen.java lblPlayers=玩家列表 lblLog=日志 diff --git a/forge-gui/src/main/java/forge/properties/ForgePreferences.java b/forge-gui/src/main/java/forge/properties/ForgePreferences.java index 8526e1ace69..d7101907172 100644 --- a/forge-gui/src/main/java/forge/properties/ForgePreferences.java +++ b/forge-gui/src/main/java/forge/properties/ForgePreferences.java @@ -144,6 +144,7 @@ public class ForgePreferences extends PreferencesStore { UI_SHOW_FPS("false"), UI_NETPLAY_COMPAT("false"), UI_LOAD_UNKNOWN_CARDS("true"), + UI_AUTO_CACHE_SIZE("false"), UI_ALLOW_ORDER_GRAVEYARD_WHEN_NEEDED ("Never"), UI_DEFAULT_FONT_SIZE("12"), UI_SELECT_FROM_CARD_DISPLAYS("true"), From 08c6c24c5fe16bd232803f26a50831cc54cac9d2 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Fri, 18 Dec 2020 08:11:31 -0500 Subject: [PATCH 54/97] magda_brazen_outlaw.txt (Marvel) --- .../cardsfolder/upcoming/magda_brazen_outlaw.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/magda_brazen_outlaw.txt diff --git a/forge-gui/res/cardsfolder/upcoming/magda_brazen_outlaw.txt b/forge-gui/res/cardsfolder/upcoming/magda_brazen_outlaw.txt new file mode 100644 index 00000000000..d5dab6f7945 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/magda_brazen_outlaw.txt @@ -0,0 +1,14 @@ +Name:Magda, Brazen Outlaw +ManaCost:1 R +Types:Legendary Creature Dwarf Berserker +PT:2/1 +S:Mode$ Continuous | Affected$ Dwarf.Other+YouCtrl | AddPower$ 1 | Description$ Other Dwarves you control get +1/+0. +T:Mode$ Taps | ValidCard$ Dwarf.YouCtrl | Execute$ TrigToken | TriggerZones$ Battlefield | TriggerDescription$ Whenever a Dwarf you control becomes tapped, create a Treasure token. +SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_a_treasure_sac | TokenOwner$ You +A:AB$ ChangeZone | Cost$ Sac<5/Treasure> | CostDesc$ Sacrifice five Treasures: | Origin$ Library | Destination$ Battlefield | ChangeType$ Card.Artifact,Card.Dragon | ChangeNum$ 1 | Mandatory$ True | StackDescription$ {p:You} searches their library for an Artifact or Dragon card, puts that card onto the battlefield, then shuffles their library. | SpellDescription$ Search your library for an Artifact or Dragon card, put that card onto the battlefield, then shuffle your library. +SVar:BuffedBy:Dwarf +SVar:PlayMain1:TRUE +DeckNeeds:Type$Dwarf +DeckHints:Type$Dragon|Artifact +DeckHas:Ability$Token & Ability$Sacrifice +Oracle:Other Dwarves you control get +1/+0. \nWhenever a Dwarf you control becomes tapped, create a treasure token. \nSacrifice five Treasures: Search your library for an Artifact or Dragon card, put that card onto the battlefield, then shuffle your library. From 000b13780d9d4d858b3d110cada23cd0d700fc28 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Fri, 18 Dec 2020 08:16:36 -0500 Subject: [PATCH 55/97] rampage_of_the_valkyries.txt (Marvel) --- .../cardsfolder/upcoming/rampage_of_the_valkyries.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/rampage_of_the_valkyries.txt diff --git a/forge-gui/res/cardsfolder/upcoming/rampage_of_the_valkyries.txt b/forge-gui/res/cardsfolder/upcoming/rampage_of_the_valkyries.txt new file mode 100644 index 00000000000..82c4de4f02f --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/rampage_of_the_valkyries.txt @@ -0,0 +1,10 @@ +Name:Rampage of the Valkyries +ManaCost:3 W B +Types:Enchantment +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield, create a 4/4 white Angel creature token with flying and vigilance. +SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_4_4_angel_flying_vigilance | TokenOwner$ You +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Angel.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigSac | TriggerDescription$ Whenever an Angel you control dies, each opponent sacrifices a creature. +SVar:TrigSac:DB$ Sacrifice | Defined$ Opponent | SacValid$ Creature +DeckHints:Type$Angel +DeckHas:Ability$Token +Oracle:When Rampage of the Valkyries enters the battlefield, create a 4/4 white Angel token with flying and vigilance.\nWhenever a creature you control dies, each opponent sacrifices a creature. From 1e3bc63ae37442f309f120a7859bf8bf19196af5 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Fri, 18 Dec 2020 08:34:07 -0500 Subject: [PATCH 56/97] renegade_reaper.txt (Marvel) --- .../res/cardsfolder/upcoming/renegade_reaper.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/renegade_reaper.txt diff --git a/forge-gui/res/cardsfolder/upcoming/renegade_reaper.txt b/forge-gui/res/cardsfolder/upcoming/renegade_reaper.txt new file mode 100644 index 00000000000..f3545f092d8 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/renegade_reaper.txt @@ -0,0 +1,12 @@ +Name:Renegade Reaper +ManaCost:2 B +Types:Creature Angel Berserker +PT:2/3 +K:Flying +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMill | TriggerDescription$ When CARDNAME enters the battlefield, mill four cards. If at least one Angel card was milled this way, you gain 4 life. +SVar:TrigMill:DB$ Mill | NumCards$ 4 | Defined$ You | RememberMilled$ True | SubAbility$ DBLifeGain +SVar:DBLifeGain:DB$ GainLife | Defined$ You | LifeAmount$ 4 | ConditionDefined$ Remembered | ConditionPresent$ Angel | ConditionCompare$ GE1 | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +DeckHints:Type$Angel +DeckHas:Ability$Mill & Ability$LifeGain +Oracle:Flying\nWhen Renegade Reaper enters the battlefield, mill four cards. If at least one Angel card is milled this way, you gain 4 life. From aa48a545b0bcc2ffbaf480657d9e9f25b76c390b Mon Sep 17 00:00:00 2001 From: Northmoc Date: Fri, 18 Dec 2020 08:38:19 -0500 Subject: [PATCH 57/97] cleaving_reaper.txt (Marvel) --- .../res/cardsfolder/upcoming/cleaving_reaper.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/cleaving_reaper.txt diff --git a/forge-gui/res/cardsfolder/upcoming/cleaving_reaper.txt b/forge-gui/res/cardsfolder/upcoming/cleaving_reaper.txt new file mode 100644 index 00000000000..bebe4535923 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/cleaving_reaper.txt @@ -0,0 +1,11 @@ +Name:Cleaving Reaper +ManaCost:3 B B +Types:Creature Angel Berserker +PT:5/3 +K:Flying +K:Trample +A:AB$ ChangeZone | Cost$ PayLife<3> | Origin$ Graveyard | Destination$ Hand | ActivationZone$ Graveyard | CheckSVar$ X | References$ X | SpellDescription$ Return CARDNAME from your graveyard to your hand. Activate this ability only if you had an Angel or Berserker enter the battlefield under your control this turn. +SVar:X:Count$ThisTurnEntered_Battlefield_Angel.YouCtrl,Berserker.YouCtrl +DeckHints:Type$Angel|Berserker +DeckHas:Ability$Graveyard +Oracle:Flying, trample\nPay 3 life: Return Cleaving Reaper from your graveyard to your hand. Activate this ability only if you had an Angel or Berserker enter the battlefield under your control this turn. From 29113f5066751905594a1c0907029c90d4d6e248 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Fri, 18 Dec 2020 08:42:20 -0500 Subject: [PATCH 58/97] valkyrie_harbinger.txt (Marvel) --- .../res/cardsfolder/upcoming/valkyrie_harbinger.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/valkyrie_harbinger.txt diff --git a/forge-gui/res/cardsfolder/upcoming/valkyrie_harbinger.txt b/forge-gui/res/cardsfolder/upcoming/valkyrie_harbinger.txt new file mode 100644 index 00000000000..cc45a829add --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/valkyrie_harbinger.txt @@ -0,0 +1,12 @@ +Name:Valkyrie Harbinger +ManaCost:4 W W +Types:Creature Angel Cleric +PT:4/5 +K:Flying +K:Lifelink +T:Mode$ Phase | Phase$ End of Turn | TriggerZones$ Battlefield | CheckSVar$ X | SVarCompare$ GE4 | Execute$ TrigToken | TriggerDescription$ At the beginning of each end step, if you gained 4 or more life this turn, create a 4/4 white Angel creature token with flying and vigilance. +SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_4_4_angel_flying_vigilance | TokenOwner$ You +SVar:X:Count$LifeYouGainedThisTurn +DeckHas:Ability$Token & Ability$LifeGain +DeckHints:Ability$LifeGain +Oracle:Flying, lifelink\nAt the beginning of each end step, if you gained 4 or more life this turn, create a 4/4 white Angel creature token with flying and vigilance. From 4b3a62f523101d4ebfa08da937ff52c675ffddfb Mon Sep 17 00:00:00 2001 From: Northmoc Date: Fri, 18 Dec 2020 08:44:40 -0500 Subject: [PATCH 59/97] youthful_valkyrie.txt (Marvel) --- .../res/cardsfolder/upcoming/youthful_valkyrie.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/youthful_valkyrie.txt diff --git a/forge-gui/res/cardsfolder/upcoming/youthful_valkyrie.txt b/forge-gui/res/cardsfolder/upcoming/youthful_valkyrie.txt new file mode 100644 index 00000000000..635cb21943a --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/youthful_valkyrie.txt @@ -0,0 +1,10 @@ +Name:Youthful Valkyrie +ManaCost:1 W +Types:Creature Angel +K:Flying +PT:1/3 +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Angel.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever another Angel enters the battlefield under your control, put a +1/+1 counter on CARDNAME. +SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 +DeckHas:Ability$Counters +DeckHints:Type$Angel +Oracle:Flying\nWhenever another Angel enters the battlefield under your control, put a +1/+1 counter on Youthful Valkyrie. From d4d5f81b695024cb7571209d21350b9807cc24ed Mon Sep 17 00:00:00 2001 From: Northmoc Date: Fri, 18 Dec 2020 11:54:33 -0500 Subject: [PATCH 60/97] sarulf_realm_eater.txt --- .../cardsfolder/upcoming/sarulf_realm_eater.txt | 14 ++++++++++++++ forge-gui/res/editions/Kaldheim.txt | 2 ++ 2 files changed, 16 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/sarulf_realm_eater.txt diff --git a/forge-gui/res/cardsfolder/upcoming/sarulf_realm_eater.txt b/forge-gui/res/cardsfolder/upcoming/sarulf_realm_eater.txt new file mode 100644 index 00000000000..36227b951cc --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/sarulf_realm_eater.txt @@ -0,0 +1,14 @@ +Name:Sarulf, Realm Eater +ManaCost:1 B G +Types:Legendary Creature Wolf +PT:3/3 +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Permanent.OppCtrl | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever a permanent an opponent controls is put into a graveyard from the battlefield, put a +1/+1 counter on CARDNAME. +SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 +T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | CheckSVar$ X | SVarCompare$ GE1 | References$ X | Execute$ TrigRemoveAll | TriggerZones$ Battlefield | OptionalDecider$ You | TriggerDescription$ At the beginning of your upkeep, if NICKNAME has one or more +1/+1 counters on it, you may remove all of them. If you do, exile each other nonland permanent with converted mana cost less than or equal to the number of counters removed this way. +SVar:TrigRemoveAll:DB$ RemoveCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ All | RememberAmount$ True | SubAbility$ DBChangeZoneAll +SVar:DBChangeZoneAll:DB$ ChangeZoneAll | Origin$ Battlefield | Destination$ Exile | ChangeType$ Permanent.nonLand+Other+cmcLEY | References$ Y | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:X:Count$CardCounters.P1P1 +SVar:Y:Count$RememberedNumber +DeckHas:Ability$Counters +Oracle:Whenever a permanent an opponent controls is put into a graveyard from the battlefield, put a +1/+1 counter on Sarulf, Realm Eater.\nAt the beginning of your upkeep, if Sarulf has one or more +1/+1 counters on it, you may remove all of them. If you do, exile each other nonland permanent with converted mana cost less than or equal to the number of counters removed this way. diff --git a/forge-gui/res/editions/Kaldheim.txt b/forge-gui/res/editions/Kaldheim.txt index 609a1597ce1..5fdf15d833b 100644 --- a/forge-gui/res/editions/Kaldheim.txt +++ b/forge-gui/res/editions/Kaldheim.txt @@ -9,6 +9,7 @@ Type=Expansion 142 R Magda, Brazen Outlaw 188 R Realmwalker 218 M Kaya the Inexorable +228 R Sarulf, Realm Eater 229 R Showdown of the Skalds 241 R Pyre of Heroes 251 R Barkchannel Pathway @@ -22,6 +23,7 @@ Type=Expansion 293 R Hengegate Pathway 299 M Halvar, God of Battle 312 R Magda, Brazen Outlaw +330 R Sarulf, Realm Eater 370 R Pyre of Heroes 374 R Valkyrie Harbinger 375 R Surtland Elementalist From a0a49c233524911b289673daf532cf8bd25c88f5 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Sat, 19 Dec 2020 19:12:15 -0500 Subject: [PATCH 61/97] realmwalker.txt --- forge-gui/res/cardsfolder/upcoming/realmwalker.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/realmwalker.txt diff --git a/forge-gui/res/cardsfolder/upcoming/realmwalker.txt b/forge-gui/res/cardsfolder/upcoming/realmwalker.txt new file mode 100644 index 00000000000..49fa31818ce --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/realmwalker.txt @@ -0,0 +1,10 @@ +Name:Realmwalker +ManaCost:2 G +Types:Creature Shapeshifter +PT:2/3 +K:Changeling +K:ETBReplacement:Other:ChooseCT +SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. +S:Mode$ Continuous | Affected$ Card.TopLibrary+YouCtrl | AffectedZone$ Library | MayLookAt$ You | Description$ You may look at the top card of your library any time. +S:Mode$ Continuous | Affected$ Creature.ChosenType+TopLibrary+YouCtrl+nonLand | AffectedZone$ Library | MayPlay$ True | Description$ You may cast creature spells of the chosen type from the top of your library. +Oracle:Changeling (This card is every creature type.)\nAs Realmwalker enters the battlefield, choose a creature type.\nYou may look at the top card of your library any time.\nYou may cast creature spells of the chosen type from the top of your library. From b026a7094d805b5be28d72a89a3cc0c5ef3f878d Mon Sep 17 00:00:00 2001 From: Northmoc Date: Mon, 21 Dec 2020 11:29:34 -0500 Subject: [PATCH 62/97] - RemoveDeck:All for now --- forge-gui/res/cardsfolder/upcoming/sarulf_realm_eater.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/forge-gui/res/cardsfolder/upcoming/sarulf_realm_eater.txt b/forge-gui/res/cardsfolder/upcoming/sarulf_realm_eater.txt index 36227b951cc..f6442d074ca 100644 --- a/forge-gui/res/cardsfolder/upcoming/sarulf_realm_eater.txt +++ b/forge-gui/res/cardsfolder/upcoming/sarulf_realm_eater.txt @@ -11,4 +11,5 @@ SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:X:Count$CardCounters.P1P1 SVar:Y:Count$RememberedNumber DeckHas:Ability$Counters +AI:RemoveDeck:All Oracle:Whenever a permanent an opponent controls is put into a graveyard from the battlefield, put a +1/+1 counter on Sarulf, Realm Eater.\nAt the beginning of your upkeep, if Sarulf has one or more +1/+1 counters on it, you may remove all of them. If you do, exile each other nonland permanent with converted mana cost less than or equal to the number of counters removed this way. From f95f0d4832bdbaafdab2cd4e620ce17ce1c6b609 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Mon, 21 Dec 2020 20:38:45 +0100 Subject: [PATCH 63/97] AbilityFactory: fix Fuse with iHasSVars --- .../src/main/java/forge/game/ability/AbilityFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/forge-game/src/main/java/forge/game/ability/AbilityFactory.java b/forge-game/src/main/java/forge/game/ability/AbilityFactory.java index d8b231bb6aa..120149338b0 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityFactory.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityFactory.java @@ -460,8 +460,8 @@ public final class AbilityFactory { Cost totalCost = parseAbilityCost(leftState, leftMap, leftType); totalCost.add(parseAbilityCost(rightState, rightMap, rightType)); - final SpellAbility left = getAbility(leftType, leftApi, leftMap, totalCost, leftState, null); - final AbilitySub right = (AbilitySub) getAbility(AbilityRecordType.SubAbility, rightApi, rightMap, null, rightState, left); + final SpellAbility left = getAbility(leftType, leftApi, leftMap, totalCost, leftState, leftState); + final AbilitySub right = (AbilitySub) getAbility(AbilityRecordType.SubAbility, rightApi, rightMap, null, rightState, rightState); left.appendSubAbility(right); return left; } From 31bca9eec309d20e18486aecf0ba4dd835693874 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Mon, 21 Dec 2020 13:17:46 -0500 Subject: [PATCH 64/97] starnheim_aspirant.txt (Marvel) --- forge-gui/res/cardsfolder/upcoming/starnheim_aspirant.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/starnheim_aspirant.txt diff --git a/forge-gui/res/cardsfolder/upcoming/starnheim_aspirant.txt b/forge-gui/res/cardsfolder/upcoming/starnheim_aspirant.txt new file mode 100644 index 00000000000..d75a242a0d4 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/starnheim_aspirant.txt @@ -0,0 +1,7 @@ +Name:Starnheim Aspirant +ManaCost:2 W +Types:Creature Human Cleric +PT:2/2 +S:Mode$ ReduceCost | EffectZone$ Battlefield | ValidCard$ Angel | Type$ Spell | Activator$ You | Amount$ 2 | Description$ Angel spells you cast cost {2} less to cast. +DeckNeeds:Type$Angel +Oracle:Angel spells you cast cost {2} less to cast. From 91854d366e8c5f80b1a07a69f7ee8b5e97194334 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Mon, 21 Dec 2020 13:19:20 -0500 Subject: [PATCH 65/97] canopy_tactician.txt (Ral) --- forge-gui/res/cardsfolder/upcoming/canopy_tactician.txt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/canopy_tactician.txt diff --git a/forge-gui/res/cardsfolder/upcoming/canopy_tactician.txt b/forge-gui/res/cardsfolder/upcoming/canopy_tactician.txt new file mode 100644 index 00000000000..d5be5d33df0 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/canopy_tactician.txt @@ -0,0 +1,8 @@ +Name:Canopy Tactician +ManaCost:3 G +Types:Creature Elf Warrior +PT:3/3 +S:Mode$ Continuous | Affected$ Elf.Other+YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Other Elves you control get +1/+1. +A:AB$ Mana | Cost$ T | Produced$ G | Amount$ 3 | SpellDescription$ Add {G}{G}{G}. +DeckHints:Type$Elf +Oracle:Other Elves you control get +1/+1.\n{T}: Add {G}{G}{G}. From 8a832cfc6871a7ad0592d4f72c988021860c456c Mon Sep 17 00:00:00 2001 From: Northmoc Date: Mon, 21 Dec 2020 13:19:42 -0500 Subject: [PATCH 66/97] Ral contrib --- forge-gui/release-files/CONTRIBUTORS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/forge-gui/release-files/CONTRIBUTORS.txt b/forge-gui/release-files/CONTRIBUTORS.txt index 7609eb480d1..b88e961289a 100644 --- a/forge-gui/release-files/CONTRIBUTORS.txt +++ b/forge-gui/release-files/CONTRIBUTORS.txt @@ -28,6 +28,7 @@ nefigah Northmoc OgreBattlecruiser pfps +Ral Ryan1729 Seravy Sirspud From a87d79c189f969a20150394dab44fe6ad57ee154 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Mon, 21 Dec 2020 13:33:01 -0500 Subject: [PATCH 67/97] giants_grasp.txt (Ral) --- forge-gui/res/cardsfolder/upcoming/giants_grasp.txt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/giants_grasp.txt diff --git a/forge-gui/res/cardsfolder/upcoming/giants_grasp.txt b/forge-gui/res/cardsfolder/upcoming/giants_grasp.txt new file mode 100644 index 00000000000..6ff381c90fb --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/giants_grasp.txt @@ -0,0 +1,9 @@ +Name:Giant's Grasp +ManaCost:2 U U +Types:Enchantment Aura +K:Enchant Giant you control +A:SP$ Attach | Cost$ 2 U U | ValidTgts$ Giant.YouCtrl | TgtPrompt$ Select Giant you control +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChange | TriggerDescription$ When CARDNAME enters the battlefield, gain control of target nonland permanent for as long as CARDNAME remains on the battlefield. +SVar:TrigChange:DB$ GainControl | TgtPrompt$ Choose target nonland permanent | ValidTgts$ Permanent.nonLand | LoseControl$ LeavesPlay +DeckNeeds:Type$Giant +Oracle:Enchant Giant you control\nWhen Giant's Grasp enters the battlefield, gain control of target nonland permanent for as long as Giant's Grasp remains on the battlefield. From 684e3351b1075a6ebe42aa06b08b267035fdb04a Mon Sep 17 00:00:00 2001 From: Northmoc Date: Mon, 21 Dec 2020 13:36:19 -0500 Subject: [PATCH 68/97] armed_and_armored.txt (medusa) --- .../res/cardsfolder/upcoming/armed_and_armored.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/armed_and_armored.txt diff --git a/forge-gui/res/cardsfolder/upcoming/armed_and_armored.txt b/forge-gui/res/cardsfolder/upcoming/armed_and_armored.txt new file mode 100644 index 00000000000..40ed10f6488 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/armed_and_armored.txt @@ -0,0 +1,12 @@ +Name:Armed and Armored +ManaCost:1 W +Types:Instant +A:SP$ AnimateAll | Cost$ 1 W | Types$ Creature,Artifact | ValidCards$ Vehicle.YouCtrl | SubAbility$ ChooseDwarf | StackDescription$ Vehicles {p:You} controls become artifact creatures until end of turn. | SpellDescription$ Vehicles you control become artifact creatures until end of turn. Choose a Dwarf you control. Attach any number of Equipment you control to it. +SVar:ChooseDwarf:DB$ ChooseCard | Defined$ You | Amount$ 1 | Choices$ Dwarf.YouCtrl | ChoiceTitle$ Choose a Dwarf you control | StackDescription$ {p:You} chooses a Dwarf they control and attaches any number of Equipment they control to it. | ImprintChosen$ True | SubAbility$ ChooseEquipment +SVar:ChooseEquipment:DB$ ChooseCard | Defined$ You | MinAmount$ 0 | Amount$ X | References$ X | Choices$ Equipment.YouCtrl | StackDescription$ None | ChoiceTitle$ Choose any number of Equipment you control | ForgetChosen$ True | SubAbility$ DeployDwarf +SVar:DeployDwarf:DB$ RepeatEach | RepeatSubAbility$ ArmDwarf | RepeatCards$ Card.ChosenCard | SubAbility$ DBCleanup +SVar:ArmDwarf:DB$ Attach | Object$ Remembered | Defined$ Imprinted | StackDescription$ None +SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True | ClearRemembered$ True | ClearImprinted$ True +SVar:X:Count$Valid Equipment.YouCtrl +AI:RemoveDeck:All +Oracle:Vehicles you control become artifact creatures until end of turn. Choose a Dwarf you control. Attach any number of Equipment you control to it. From 4e70ccac2be6e1b94c107e5d9bfe45e876ed695a Mon Sep 17 00:00:00 2001 From: Northmoc Date: Mon, 21 Dec 2020 13:42:54 -0500 Subject: [PATCH 69/97] armed_and_armored.txt AI just in case --- forge-gui/res/cardsfolder/upcoming/armed_and_armored.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/forge-gui/res/cardsfolder/upcoming/armed_and_armored.txt b/forge-gui/res/cardsfolder/upcoming/armed_and_armored.txt index 40ed10f6488..be255a89fd2 100644 --- a/forge-gui/res/cardsfolder/upcoming/armed_and_armored.txt +++ b/forge-gui/res/cardsfolder/upcoming/armed_and_armored.txt @@ -8,5 +8,7 @@ SVar:DeployDwarf:DB$ RepeatEach | RepeatSubAbility$ ArmDwarf | RepeatCards$ Card SVar:ArmDwarf:DB$ Attach | Object$ Remembered | Defined$ Imprinted | StackDescription$ None SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True | ClearRemembered$ True | ClearImprinted$ True SVar:X:Count$Valid Equipment.YouCtrl +DeckNeeds:Type$Vehicle|Dwarf +DeckHints:Type$Equipment AI:RemoveDeck:All Oracle:Vehicles you control become artifact creatures until end of turn. Choose a Dwarf you control. Attach any number of Equipment you control to it. From d5821b9d153158b2f2e8fd30267da84b28b37289 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Mon, 21 Dec 2020 13:44:54 -0500 Subject: [PATCH 70/97] pyre_of_heroes.txt (medusa) --- forge-gui/res/cardsfolder/upcoming/pyre_of_heroes.txt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/pyre_of_heroes.txt diff --git a/forge-gui/res/cardsfolder/upcoming/pyre_of_heroes.txt b/forge-gui/res/cardsfolder/upcoming/pyre_of_heroes.txt new file mode 100644 index 00000000000..b4cdfad88c9 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/pyre_of_heroes.txt @@ -0,0 +1,9 @@ +Name:Pyre of Heroes +ManaCost:2 +Types:Artifact +A:AB$ ChangeZone | Cost$ 2 T Sac<1/Creature> | RememberCostCards$ True | Origin$ Library | Destination$ Battlefield | ChangeType$ Creature.cmcEQX+sharesCreatureTypeWith Remembered | References$ X | ChangeNum$ 1 | SorcerySpeed$ True | AILogic$ SacAndUpgrade | StackDescription$ Search your library for a creature card that shares a creature type with the sacrificed creature and has converted mana cost equal to 1 plus that creature's converted mana cost. Put that card onto the battlefield, then shuffle your library. | SubAbility$ DBCleanup | SpellDescription$ Search your library for a creature card that shares a creature type with the sacrificed creature and has converted mana cost equal to 1 plus that creature's converted mana cost. Put that card onto the battlefield, then shuffle your library. Activate this ability only any time you could cast a sorcery. +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:X:Remembered$CardManaCost/Plus.1 +SVar:AIPreference:SacCost$Creature +DeckHas:Ability$Sacrifice +Oracle:{2}, {T}, Sacrifice a creature: Search your library for a creature card that shares a creature type with the sacrificed creature and has converted mana cost equal to 1 plus that creature's converted mana cost. Put that card onto the battlefield, then shuffle your library. Activate this ability only any time you could cast a sorcery. From dc6532a1844f9effc62127ccc98e27dcc93d8951 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Mon, 21 Dec 2020 13:45:38 -0500 Subject: [PATCH 71/97] pyre_of_heroes.txt +DeckNeeds --- forge-gui/res/cardsfolder/upcoming/pyre_of_heroes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/forge-gui/res/cardsfolder/upcoming/pyre_of_heroes.txt b/forge-gui/res/cardsfolder/upcoming/pyre_of_heroes.txt index b4cdfad88c9..c8f8f640ada 100644 --- a/forge-gui/res/cardsfolder/upcoming/pyre_of_heroes.txt +++ b/forge-gui/res/cardsfolder/upcoming/pyre_of_heroes.txt @@ -6,4 +6,5 @@ SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:X:Remembered$CardManaCost/Plus.1 SVar:AIPreference:SacCost$Creature DeckHas:Ability$Sacrifice +DeckNeeds:Type$Creature Oracle:{2}, {T}, Sacrifice a creature: Search your library for a creature card that shares a creature type with the sacrificed creature and has converted mana cost equal to 1 plus that creature's converted mana cost. Put that card onto the battlefield, then shuffle your library. Activate this ability only any time you could cast a sorcery. From 4461eb70b224e31786279078d4d64e848aa1068a Mon Sep 17 00:00:00 2001 From: Northmoc Date: Mon, 21 Dec 2020 13:48:08 -0500 Subject: [PATCH 72/97] surtland_elementalist.txt (medusa) --- .../res/cardsfolder/upcoming/surtland_elementalist.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/surtland_elementalist.txt diff --git a/forge-gui/res/cardsfolder/upcoming/surtland_elementalist.txt b/forge-gui/res/cardsfolder/upcoming/surtland_elementalist.txt new file mode 100644 index 00000000000..8c2518b1fa7 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/surtland_elementalist.txt @@ -0,0 +1,10 @@ +Name:Surtland Elementalist +ManaCost:5 U U +Types:Creature Giant Wizard +PT:8/8 +K:AlternateAdditionalCost:Reveal<1/Giant/Giant>:2 +T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigPlay | TriggerDescription$ Whenever CARDNAME attacks, you may cast an instant or sorcery spell from your hand without paying its mana cost. +SVar:TrigPlay:DB$ Play | ValidZone$ Hand | Valid$ Instant.YouOwn,Sorcery.YouOwn | Controller$ You | WithoutManaCost$ True | Optional$ True +SVar:HasAttackEffect:TRUE +DeckHints:Type$Instant|Sorcery|Giant +Oracle:As an additional cost to cast this spell, reveal a Giant card from your hand or pay {2}.\nWhenever Surtland Elementalist attacks, you may cast an instant or sorcery spell from your hand without paying its mana cost. From b49b075ce06247a23a64f8f01bc61da57663e6d9 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Mon, 21 Dec 2020 17:08:06 -0500 Subject: [PATCH 73/97] warchanter_skald.txt and token --- .../res/cardsfolder/upcoming/warchanter_skald.txt | 11 +++++++++++ forge-gui/res/tokenscripts/r_2_1_dwarf_berserker.txt | 6 ++++++ 2 files changed, 17 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/warchanter_skald.txt create mode 100644 forge-gui/res/tokenscripts/r_2_1_dwarf_berserker.txt diff --git a/forge-gui/res/cardsfolder/upcoming/warchanter_skald.txt b/forge-gui/res/cardsfolder/upcoming/warchanter_skald.txt new file mode 100644 index 00000000000..57cbe5c30bc --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/warchanter_skald.txt @@ -0,0 +1,11 @@ +Name:Warchanter Skald +ManaCost:2 W +Types:Creature Dwarf Cleric +PT:2/3 +T:Mode$ Taps | ValidCard$ Card.Self+enchanted,Card.Self+equipped | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever Warchanter Skald becomes tapped, if it's enchanted or equipped, create a 2/1 red Dwarf Berserker creature token. +SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ r_2_1_dwarf_berserker | TokenOwner$ You +SVar:EnchantMe:Once +SVar:EquipMe:Once +DeckNeeds:Type$Enchantment|Equipment +DeckHas:Ability$Token +Oracle:Whenever Warchanter Skald becomes tapped, if it's enchanted or equipped, create a 2/1 red Dwarf Berserker creature token. diff --git a/forge-gui/res/tokenscripts/r_2_1_dwarf_berserker.txt b/forge-gui/res/tokenscripts/r_2_1_dwarf_berserker.txt new file mode 100644 index 00000000000..556b17128fe --- /dev/null +++ b/forge-gui/res/tokenscripts/r_2_1_dwarf_berserker.txt @@ -0,0 +1,6 @@ +Name:Dwarf Berserker +ManaCost:no cost +Types:Creature Dwarf Berserker +Colors:red +PT:2/1 +Oracle: From dab5922aad19c5f873659250e280dad3c837c15f Mon Sep 17 00:00:00 2001 From: Northmoc Date: Tue, 22 Dec 2020 12:32:15 -0500 Subject: [PATCH 74/97] magma_phoenix.txt typo --- forge-gui/res/cardsfolder/m/magma_phoenix.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/forge-gui/res/cardsfolder/m/magma_phoenix.txt b/forge-gui/res/cardsfolder/m/magma_phoenix.txt index 8eb4e3da240..fc92728e375 100644 --- a/forge-gui/res/cardsfolder/m/magma_phoenix.txt +++ b/forge-gui/res/cardsfolder/m/magma_phoenix.txt @@ -3,9 +3,8 @@ ManaCost:3 R R Types:Creature Phoenix PT:3/3 K:Flying -A:AB$ ChangeZone | Cost$ 3 R R | Origin$ Graveyard | Destination$ Hand | ActivationZone$ Graveyard | SpellDescription$ Return CARDNAME from your graveyard to the hand. +A:AB$ ChangeZone | Cost$ 3 R R | Origin$ Graveyard | Destination$ Hand | ActivationZone$ Graveyard | SpellDescription$ Return CARDNAME from your graveyard to your hand. T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigDamage | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, it deals 3 damage to each creature and each player. SVar:TrigDamage:DB$ DamageAll | ValidCards$ Creature | ValidPlayers$ Player | NumDmg$ 3 | ValidDescription$ each creature and each player. SVar:DiscardMe:2 -SVar:Picture:http://www.wizards.com/global/images/magic/general/magma_phoenix.jpg Oracle:Flying\nWhen Magma Phoenix dies, it deals 3 damage to each creature and each player.\n{3}{R}{R}: Return Magma Phoenix from your graveyard to your hand. From d402de260c3a2eb24a3ed1401aa7c7288b8f8837 Mon Sep 17 00:00:00 2001 From: Andreas Bendel Date: Tue, 22 Dec 2020 19:47:02 +0000 Subject: [PATCH 75/97] Update de-DE.properties translation - lblAutoCacheSize and nlAutoCacheSize --- forge-gui/res/languages/de-DE.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/forge-gui/res/languages/de-DE.properties b/forge-gui/res/languages/de-DE.properties index d0ca05955e3..45a2f6bfd0d 100644 --- a/forge-gui/res/languages/de-DE.properties +++ b/forge-gui/res/languages/de-DE.properties @@ -994,8 +994,8 @@ lblEnableUnknownCards=Erlaube unbekannte Karten nlEnableUnknownCards=Erlaube unbekannte Karten von unbekannten Sets. (Erfordert Neustart) lblExperimentalNetworkCompatibility=Experimentelle Netzwerkkompatibilität nlExperimentalNetworkCompatibility=Forge wechselt auf kompatiblen Netzwerk-Stream. (Im Zweifel bitte ausschalten) -lblAutoCacheSize=Enable Auto Cache Size -nlAutoCacheSize=When enabled, Cache size are automatically determined on startup. (If unsure, turn OFF this option) +lblAutoCacheSize=Aktiviere automatische Cache-Größe +nlAutoCacheSize=Wenn aktiviert, wird die Cache-Größe beim Start automatisch ermittelt und eingestellt. (Im Zweifel bitte ausschalten) #MatchScreen.java lblPlayers=Spieler lblLog=Bericht From ecc6a65b1dbcf8ded7dc095450b2e77b8b0cfed4 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Tue, 22 Dec 2020 16:17:04 -0500 Subject: [PATCH 76/97] Show card owner if being controlled by a different player --- forge-gui/src/main/java/forge/card/CardDetailUtil.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/forge-gui/src/main/java/forge/card/CardDetailUtil.java b/forge-gui/src/main/java/forge/card/CardDetailUtil.java index 1c994076c42..18597a7e7e4 100644 --- a/forge-gui/src/main/java/forge/card/CardDetailUtil.java +++ b/forge-gui/src/main/java/forge/card/CardDetailUtil.java @@ -569,6 +569,14 @@ public class CardDetailUtil { area.append("Current Storm Count: ").append(gameView.getStormCount()); } } + + //show owner if being controlled by a different player + if (card.getOwner() != card.getController()) { + if (area.length() != 0) { + area.append("\n\n"); + } + area.append("Owner: ").append(card.getOwner().toString()); + } return area.toString(); } } From 38309086f3d68133695a44cde1d90afddc68f155 Mon Sep 17 00:00:00 2001 From: CCTV-1 Date: Wed, 23 Dec 2020 12:46:38 +0800 Subject: [PATCH 77/97] translate new setting --- forge-gui/res/languages/zh-CN.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/forge-gui/res/languages/zh-CN.properties b/forge-gui/res/languages/zh-CN.properties index 020724d593a..0441ac02e3c 100644 --- a/forge-gui/res/languages/zh-CN.properties +++ b/forge-gui/res/languages/zh-CN.properties @@ -993,9 +993,9 @@ nlShowFPSDisplay=启用后,将在画面左上角显示当前Forge的FPS(实 lblEnableUnknownCards=启用未知卡牌 nlEnableUnknownCards=将未知卡牌加载到未知系列中。(需要重启) lblExperimentalNetworkCompatibility=实验性网络兼容 -nlExperimentalNetworkCompatibility=Forge将切换为兼容性的网络流。(如果不清楚,请关闭此选项) -lblAutoCacheSize=Enable Auto Cache Size -nlAutoCacheSize=When enabled, Cache size are automatically determined on startup. (If unsure, turn OFF this option) +nlExperimentalNetworkCompatibility=Forge将切换为兼容性的网络流。(如果不清楚此选项的作用,请关闭此选项) +lblAutoCacheSize=启用自动缓存大小 +nlAutoCacheSize=启用后,Forge将于启动时自动确定缓存大小。(如果不清楚此选项的作用,请关闭此选项) #MatchScreen.java lblPlayers=玩家列表 lblLog=日志 From bbf788594fac79eb3f6f8c4456dfae4490bdd173 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Wed, 23 Dec 2020 08:05:26 +0000 Subject: [PATCH 78/97] CostRemoveCounter + CostRemoveAnyCounter: refactor remove X counters from something you control --- .../src/main/java/forge/ai/AiController.java | 6 +- .../main/java/forge/ai/AiCostDecision.java | 355 ++++++++++-------- .../src/main/java/forge/ai/ComputerUtil.java | 14 +- .../main/java/forge/ai/ComputerUtilCost.java | 46 ++- .../main/java/forge/ai/ComputerUtilMana.java | 17 +- .../src/main/java/forge/ai/SpecialCardAi.java | 2 +- .../main/java/forge/ai/SpellAbilityAi.java | 6 - .../main/java/forge/ai/ability/AttachAi.java | 4 +- .../java/forge/ai/ability/ChangeZoneAi.java | 18 +- .../java/forge/ai/ability/ChooseColorAi.java | 2 +- .../java/forge/ai/ability/ChooseSourceAi.java | 2 +- .../java/forge/ai/ability/ControlGainAi.java | 2 +- .../main/java/forge/ai/ability/CounterAi.java | 8 +- .../java/forge/ai/ability/CountersPutAi.java | 12 +- .../forge/ai/ability/CountersPutAllAi.java | 4 +- .../ai/ability/CountersPutOrRemoveAi.java | 2 +- .../forge/ai/ability/CountersRemoveAi.java | 10 +- .../java/forge/ai/ability/DamageAllAi.java | 6 +- .../java/forge/ai/ability/DamageDealAi.java | 39 +- .../forge/ai/ability/DamagePreventAi.java | 2 +- .../forge/ai/ability/DamagePreventAllAi.java | 2 +- .../main/java/forge/ai/ability/DebuffAi.java | 6 +- .../main/java/forge/ai/ability/DestroyAi.java | 2 +- .../java/forge/ai/ability/DestroyAllAi.java | 4 +- .../src/main/java/forge/ai/ability/DigAi.java | 6 +- .../java/forge/ai/ability/DigUntilAi.java | 6 +- .../main/java/forge/ai/ability/DiscardAi.java | 6 +- .../main/java/forge/ai/ability/DrawAi.java | 14 +- .../java/forge/ai/ability/LifeGainAi.java | 11 +- .../java/forge/ai/ability/LifeLoseAi.java | 19 +- .../main/java/forge/ai/ability/LifeSetAi.java | 10 +- .../java/forge/ai/ability/ManifestAi.java | 2 +- .../main/java/forge/ai/ability/MillAi.java | 10 +- .../main/java/forge/ai/ability/ProtectAi.java | 9 +- .../java/forge/ai/ability/ProtectAllAi.java | 2 +- .../main/java/forge/ai/ability/PumpAi.java | 84 ++--- .../main/java/forge/ai/ability/RepeatAi.java | 8 +- .../java/forge/ai/ability/SacrificeAi.java | 6 +- .../java/forge/ai/ability/SacrificeAllAi.java | 4 +- .../java/forge/ai/ability/StoreSVarAi.java | 2 +- .../src/main/java/forge/ai/ability/TapAi.java | 35 +- .../main/java/forge/ai/ability/TapAiBase.java | 59 ++- .../java/forge/ai/ability/TapOrUntapAi.java | 11 +- .../main/java/forge/ai/ability/TokenAi.java | 8 +- .../java/forge/ai/ability/UnattachAllAi.java | 2 +- .../main/java/forge/ai/ability/UntapAi.java | 24 +- .../src/main/java/forge/game/ForgeScript.java | 2 +- .../src/main/java/forge/game/GameAction.java | 6 - .../forge/game/GameEntityCounterTable.java | 34 +- .../src/main/java/forge/game/card/Card.java | 11 - .../java/forge/game/card/CardFactoryUtil.java | 45 --- .../java/forge/game/card/CardProperty.java | 2 +- .../java/forge/game/card/CounterType.java | 3 + .../src/main/java/forge/game/cost/Cost.java | 76 ++-- .../main/java/forge/game/cost/CostPart.java | 39 +- .../java/forge/game/cost/CostPayEnergy.java | 4 + .../forge/game/cost/CostRemoveAnyCounter.java | 116 ++---- .../forge/game/cost/CostRemoveCounter.java | 100 +++-- .../java/forge/game/cost/PaymentDecision.java | 55 +-- .../game/spellability/AbilityActivated.java | 4 +- .../game/spellability/AbilityManaPart.java | 2 +- .../game/spellability/AbilityStatic.java | 4 +- .../forge/game/spellability/SpellAbility.java | 25 +- .../spellability/SpellAbilityCondition.java | 3 +- .../game/spellability/TargetRestrictions.java | 27 +- .../main/java/forge/game/zone/MagicStack.java | 5 +- .../res/cardsfolder/b/blademane_baku.txt | 8 +- .../res/cardsfolder/c/chamber_sentry.txt | 2 +- .../cardsfolder/c/chisei_heart_of_oceans.txt | 4 +- .../cardsfolder/g/garruk_primal_hunter.txt | 1 - .../res/cardsfolder/h/huatli_warrior_poet.txt | 3 +- forge-gui/res/cardsfolder/n/novijen_sages.txt | 3 +- forge-gui/res/cardsfolder/o/ooze_flux.txt | 3 +- .../res/cardsfolder/p/petalmane_baku.txt | 8 +- forge-gui/res/cardsfolder/p/power_conduit.txt | 3 +- .../res/cardsfolder/q/quillmane_baku.txt | 8 +- .../r/retribution_of_the_ancients.txt | 3 +- .../res/cardsfolder/s/skullmane_baku.txt | 8 +- forge-gui/res/cardsfolder/s/soul_diviner.txt | 2 +- .../upcoming/tayam_luminous_enigma.txt | 12 + forge-gui/res/cardsfolder/w/waxmane_baku.txt | 7 +- .../java/forge/player/HumanCostDecision.java | 155 ++++---- .../src/main/java/forge/player/HumanPlay.java | 76 +--- .../forge/player/HumanPlaySpellAbility.java | 12 +- .../forge/player/PlayerControllerHuman.java | 23 +- .../java/forge/player/TargetSelection.java | 5 +- 86 files changed, 835 insertions(+), 983 deletions(-) create mode 100644 forge-gui/res/cardsfolder/upcoming/tayam_luminous_enigma.txt diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index b54c6344cbb..7421fa0cffb 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -751,7 +751,7 @@ public class AiController { if (xPay <= 0) { return AiPlayDecision.CantAffordX; } - card.setSVar("PayX", Integer.toString(xPay)); + sa.setSVar("PayX", Integer.toString(xPay)); } else if (mana.isZero()) { // if mana is zero, but card mana cost does have X, then something is wrong ManaCost cardCost = card.getManaCost(); @@ -1061,8 +1061,8 @@ public class AiController { } else if ("VolrathsShapeshifter".equals(sa.getParam("AILogic"))) { return SpecialCardAi.VolrathsShapeshifter.targetBestCreature(player, sa); } else if ("DiscardCMCX".equals(sa.getParam("AILogic"))) { - final int CMC = Integer.parseInt(sourceCard.getSVar("PayX")); - CardCollection discards = CardLists.filter(player.getCardsIn(ZoneType.Hand), CardPredicates.hasCMC(CMC)); + final int cmc = Integer.parseInt(sa.getSVar("PayX")); + CardCollection discards = CardLists.filter(player.getCardsIn(ZoneType.Hand), CardPredicates.hasCMC(cmc)); if (discards.isEmpty()) { return null; } else { diff --git a/forge-ai/src/main/java/forge/ai/AiCostDecision.java b/forge-ai/src/main/java/forge/ai/AiCostDecision.java index c2b8c9cf691..f5c43be501f 100644 --- a/forge-ai/src/main/java/forge/ai/AiCostDecision.java +++ b/forge-ai/src/main/java/forge/ai/AiCostDecision.java @@ -4,12 +4,15 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import org.apache.commons.lang3.ObjectUtils; + import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Lists; import forge.card.CardType; import forge.game.Game; +import forge.game.GameEntityCounterTable; import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CardCollection; @@ -20,6 +23,7 @@ import forge.game.card.CardPredicates.Presets; import forge.game.card.CounterEnumType; import forge.game.card.CounterType; import forge.game.cost.*; +import forge.game.keyword.Keyword; import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbilityStackInstance; @@ -31,7 +35,7 @@ import forge.util.collect.FCollectionView; public class AiCostDecision extends CostDecisionMakerBase { private final SpellAbility ability; private final Card source; - + private final CardCollection discarded; private final CardCollection tapped; @@ -47,11 +51,11 @@ public class AiCostDecision extends CostDecisionMakerBase { @Override public PaymentDecision visit(CostAddMana cost) { Integer c = cost.convertAmount(); - + if (c == null) { c = AbilityUtils.calculateAmount(source, cost.getAmount(), ability); } - + return PaymentDecision.number(c); } @@ -321,17 +325,17 @@ public class AiCostDecision extends CostDecisionMakerBase { @Override public PaymentDecision visit(CostGainLife cost) { final List oppsThatCanGainLife = Lists.newArrayList(); - + for (final Player opp : cost.getPotentialTargets(player, source)) { if (opp.canGainLife()) { oppsThatCanGainLife.add(opp); } } - + if (oppsThatCanGainLife.size() == 0) { return null; } - + return PaymentDecision.players(oppsThatCanGainLife); } @@ -587,7 +591,7 @@ public class AiCostDecision extends CostDecisionMakerBase { public PaymentDecision visit(CostReturn cost) { if (cost.payCostFromSource()) return PaymentDecision.card(source); - + Integer c = cost.convertAmount(); if (c == null) { c = AbilityUtils.calculateAmount(source, cost.getAmount(), ability); @@ -616,7 +620,7 @@ public class AiCostDecision extends CostDecisionMakerBase { if (cost.getType().equals("SameColor")) { return null; } - + hand = CardLists.getValidCards(hand, type.split(";"), player, source, ability); Integer c = cost.convertAmount(); if (c == null) { @@ -632,60 +636,162 @@ public class AiCostDecision extends CostDecisionMakerBase { return PaymentDecision.card(aic.getCardsToDiscard(c, type.split(";"), ability)); } + protected int removeCounter(GameEntityCounterTable table, List prefs, CounterEnumType cType, int stillToRemove) { + int removed = 0; + if (!prefs.isEmpty() && stillToRemove > 0) { + Collections.sort(prefs, CardPredicates.compareByCounterType(cType)); + + for (Card prefCard : prefs) { + // already enough removed + if (stillToRemove <= removed) { + break; + } + int thisRemove = Math.min(prefCard.getCounters(cType), stillToRemove); + if (thisRemove > 0) { + removed += thisRemove; + table.put(prefCard, CounterType.get(cType), thisRemove); + } + } + } + return removed; + } + @Override public PaymentDecision visit(CostRemoveAnyCounter cost) { final String amount = cost.getAmount(); final int c = AbilityUtils.calculateAmount(source, amount, ability); - final String type = cost.getType(); + final Card originalHost = ObjectUtils.defaultIfNull(ability.getOriginalHost(), source); - CardCollectionView typeList = CardLists.getValidCards(player.getCardsIn(ZoneType.Battlefield), type.split(";"), player, source, ability); + if (c <= 0) { + return null; + } + + CardCollectionView typeList = CardLists.getValidCards(player.getCardsIn(ZoneType.Battlefield), cost.getType().split(";"), player, source, ability); + // only cards with counters are of interest + typeList = CardLists.filter(typeList, CardPredicates.hasCounters()); // no target if (typeList.isEmpty()) { return null; } + // TODO fill up a GameEntityCounterTable + // cost now has counter type or null + // the amount might be different from 1, could be X + // currently if amount is bigger than one, + // it tries to remove all counters from one source and type at once + + + int toRemove = 0; + final GameEntityCounterTable table = new GameEntityCounterTable(); + + // currently the only one using remove any counter using a type uses p1p1 + // the first things are benefit from removing counters - // try to remove +1/+1 counter from undying creature - List prefs = CardLists.filter(typeList, CardPredicates.hasCounter(CounterEnumType.P1P1, c), - CardPredicates.hasKeyword("Undying")); - - if (!prefs.isEmpty()) { - Collections.sort(prefs, CardPredicates.compareByCounterType(CounterEnumType.P1P1)); - PaymentDecision result = PaymentDecision.card(prefs); - result.ct = CounterType.get(CounterEnumType.P1P1); - return result; - } - // try to remove -1/-1 counter from persist creature - prefs = CardLists.filter(typeList, CardPredicates.hasCounter(CounterEnumType.M1M1, c), - CardPredicates.hasKeyword("Persist")); + if (c > toRemove && (cost.counter == null || cost.counter.is(CounterEnumType.M1M1))) { + List prefs = CardLists.filter(typeList, CardPredicates.hasCounter(CounterEnumType.M1M1), CardPredicates.hasKeyword(Keyword.PERSIST)); - if (!prefs.isEmpty()) { - Collections.sort(prefs, CardPredicates.compareByCounterType(CounterEnumType.M1M1)); - PaymentDecision result = PaymentDecision.card(prefs); - result.ct = CounterType.get(CounterEnumType.M1M1); - return result; + toRemove += removeCounter(table, prefs, CounterEnumType.M1M1, c - toRemove); } - // try to remove Time counter from Chronozoa, it will generate more - prefs = CardLists.filter(typeList, CardPredicates.hasCounter(CounterEnumType.TIME, c), - CardPredicates.nameEquals("Chronozoa")); + // try to remove +1/+1 counter from undying creature + if (c > toRemove && (cost.counter == null || cost.counter.is(CounterEnumType.P1P1))) { + List prefs = CardLists.filter(typeList, CardPredicates.hasCounter(CounterEnumType.P1P1), CardPredicates.hasKeyword(Keyword.UNDYING)); - if (!prefs.isEmpty()) { - Collections.sort(prefs, CardPredicates.compareByCounterType(CounterEnumType.TIME)); - PaymentDecision result = PaymentDecision.card(prefs); - result.ct = CounterType.get(CounterEnumType.TIME); - return result; + toRemove += removeCounter(table, prefs, CounterEnumType.P1P1, c - toRemove); + } + + if (c > toRemove && cost.counter == null && originalHost.hasSVar("AIRemoveCounterCostPriority") && !"ANY".equalsIgnoreCase(originalHost.getSVar("AIRemoveCounterCostPriority"))) { + String[] counters = TextUtil.split(originalHost.getSVar("AIRemoveCounterCostPriority"), ','); + + for (final String ctr : counters) { + CounterType ctype = CounterType.getType(ctr); + // ctype == null means any type + // any type is just used to return null for this + + for (Card card : CardLists.filter(typeList, CardPredicates.hasCounter(ctype))) { + int thisRemove = Math.min(card.getCounters(ctype), c - toRemove); + if (thisRemove > 0) { + toRemove += thisRemove; + table.put(card, ctype, thisRemove); + } + } + } + } + + // filter for negative counters + if (c > toRemove && cost.counter == null) { + List negatives = CardLists.filter(typeList, new Predicate() { + @Override + public boolean apply(final Card crd) { + for (CounterType cType : table.filterToRemove(crd).keySet()) { + if (ComputerUtil.isNegativeCounter(cType, crd)) { + return true; + } + } + return false; + } + }); + + if (!negatives.isEmpty()) { + // TODO sort negatives to remove from best Cards first? + for (final Card crd : negatives) { + for (Map.Entry e : table.filterToRemove(crd).entrySet()) { + if (ComputerUtil.isNegativeCounter(e.getKey(), crd)) { + int over = Math.min(e.getValue(), c - toRemove); + if (over > 0) { + toRemove += over; + table.put(crd, e.getKey(), over); + } + } + } + } + } + } + + // filter for useless counters + // they have no effect on the card, if they are there or removed + if (c > toRemove && cost.counter == null) { + List useless = CardLists.filter(typeList, new Predicate() { + @Override + public boolean apply(final Card crd) { + for (CounterType ctype : table.filterToRemove(crd).keySet()) { + if (ComputerUtil.isUselessCounter(ctype, crd)) { + return true; + } + } + return false; + } + }); + + if (!useless.isEmpty()) { + for (final Card crd : useless) { + for (Map.Entry e : table.filterToRemove(crd).entrySet()) { + if (ComputerUtil.isUselessCounter(e.getKey(), crd)) { + int over = Math.min(e.getValue(), c - toRemove); + if (over > 0) { + toRemove += over; + table.put(crd, e.getKey(), over); + } + } + } + } + } + } + + // try to remove Time counter from Chronozoa, it will generate more token + if (c > toRemove && (cost.counter == null || cost.counter.is(CounterEnumType.TIME))) { + List prefs = CardLists.filter(typeList, CardPredicates.hasCounter(CounterEnumType.TIME), CardPredicates.nameEquals("Chronozoa")); + + toRemove += removeCounter(table, prefs, CounterEnumType.TIME, c - toRemove); } // try to remove Quest counter on something with enough counters for the // effect to continue - prefs = CardLists.filter(typeList, CardPredicates.hasCounter(CounterEnumType.QUEST, c)); - - if (!prefs.isEmpty()) { - prefs = CardLists.filter(prefs, new Predicate() { + if (c > toRemove && (cost.counter == null || cost.counter.is(CounterEnumType.QUEST))) { + List prefs = CardLists.filter(typeList, new Predicate() { @Override public boolean apply(final Card crd) { // a Card without MaxQuestEffect doesn't need any Quest @@ -694,130 +800,65 @@ public class AiCostDecision extends CostDecisionMakerBase { if (crd.hasSVar("MaxQuestEffect")) { e = Integer.parseInt(crd.getSVar("MaxQuestEffect")); } - return crd.getCounters(CounterEnumType.QUEST) >= e + c; + return crd.getCounters(CounterEnumType.QUEST) > e; } }); Collections.sort(prefs, Collections.reverseOrder(CardPredicates.compareByCounterType(CounterEnumType.QUEST))); - PaymentDecision result = PaymentDecision.card(prefs); - result.ct = CounterType.get(CounterEnumType.QUEST); - return result; + + for (final Card crd : prefs) { + int e = 0; + if (crd.hasSVar("MaxQuestEffect")) { + e = Integer.parseInt(crd.getSVar("MaxQuestEffect")); + } + int over = Math.min(crd.getCounters(CounterEnumType.QUEST) - e, c - toRemove); + if (over > 0) { + toRemove += over; + table.put(crd, CounterType.get(CounterEnumType.QUEST), over); + } + } } - // filter for only cards with enough counters - typeList = CardLists.filter(typeList, new Predicate() { - @Override - public boolean apply(final Card crd) { - for (Integer i : crd.getCounters().values()) { - if (i >= c) { - return true; + // remove Lore counters from Sagas to keep them longer + if (c > toRemove && (cost.counter == null || cost.counter.is(CounterEnumType.LORE))) { + List prefs = CardLists.filter(typeList, CardPredicates.hasCounter(CounterEnumType.LORE), CardPredicates.isType("Saga")); + // TODO add Svars and other stuff to keep the Sagas on specific levels + // also add a way for the AI to respond to the last Chapter ability to keep the Saga on the field if wanted + toRemove += removeCounter(table, prefs, CounterEnumType.LORE, c - toRemove); + } + + + // TODO add logic to remove positive counters? + if (c > toRemove && cost.counter != null) { + // TODO add logic for Ooze Flux, should probably try to make a token as big as possible + // without killing own non undying creatures in the process + // the amount of X should probably be tweaked for this + List withCtr = CardLists.filter(typeList, CardPredicates.hasCounter(cost.counter)); + for (Card card : withCtr) { + int thisRemove = Math.min(card.getCounters(cost.counter), c - toRemove); + if (thisRemove > 0) { + toRemove += thisRemove; + table.put(card, cost.counter, thisRemove); + } + } + } + + // Used to not return null + // Special part for CostPriority Any + if (c > toRemove && cost.counter == null && originalHost.hasSVar("AIRemoveCounterCostPriority") && "ANY".equalsIgnoreCase(originalHost.getSVar("AIRemoveCounterCostPriority"))) { + for (Card card : typeList) { + // TODO try not to remove to much positive counters from the same card + for (Map.Entry e : table.filterToRemove(card).entrySet()) { + int thisRemove = Math.min(e.getValue(), c - toRemove); + if (thisRemove > 0) { + toRemove += thisRemove; + table.put(card, e.getKey(), thisRemove); } } - return false; - } - }); - - // nothing with enough counters of any type - if (typeList.isEmpty()) { - return null; - } - - // filter for negative counters - List negatives = CardLists.filter(typeList, new Predicate() { - @Override - public boolean apply(final Card crd) { - for (Map.Entry e : crd.getCounters().entrySet()) { - if (e.getValue() >= c && ComputerUtil.isNegativeCounter(e.getKey(), crd)) { - return true; - } - } - return false; - } - }); - - if (!negatives.isEmpty()) { - final Card card = ComputerUtilCard.getBestAI(negatives); - PaymentDecision result = PaymentDecision.card(card); - - for (Map.Entry e : card.getCounters().entrySet()) { - if (e.getValue() >= c && ComputerUtil.isNegativeCounter(e.getKey(), card)) { - result.ct = e.getKey(); - break; - } - } - return result; - } - - // filter for useless counters - // they have no effect on the card, if they are there or removed - List useless = CardLists.filter(typeList, new Predicate() { - @Override - public boolean apply(final Card crd) { - for (Map.Entry e : crd.getCounters().entrySet()) { - if (e.getValue() >= c && ComputerUtil.isUselessCounter(e.getKey())) { - return true; - } - } - return false; - } - }); - - if (!useless.isEmpty()) { - final Card card = useless.get(0); - PaymentDecision result = PaymentDecision.card(card); - - for (Map.Entry e : card.getCounters().entrySet()) { - if (e.getValue() >= c && ComputerUtil.isUselessCounter(e.getKey())) { - result.ct = e.getKey(); - break; - } - } - return result; - } - - // try a way to pay unless cost - if ("Chisei, Heart of Oceans".equals(ComputerUtilAbility.getAbilitySourceName(ability))) { - final Card card = ComputerUtilCard.getWorstAI(typeList); - PaymentDecision result = PaymentDecision.card(card); - for (Map.Entry e : card.getCounters().entrySet()) { - if (e.getValue() >= c) { - result.ct = e.getKey(); - break; - } - } - return result; - } - - // check if the card defines its own priorities for counter removal as cost - if (source.hasSVar("AIRemoveCounterCostPriority")) { - String[] counters = TextUtil.split(source.getSVar("AIRemoveCounterCostPriority"), ','); - - for (final String ctr : counters) { - List withCtr = CardLists.filter(typeList, new Predicate() { - @Override - public boolean apply(final Card crd) { - for (Map.Entry e : crd.getCounters().entrySet()) { - if (e.getValue() >= c && (ctr.equals("ANY") || e.getKey().equals(CounterType.getType(ctr)))) { - return true; - } - } - return false; - } - }); - if (!withCtr.isEmpty()) { - final Card card = withCtr.get(0); - PaymentDecision result = PaymentDecision.card(card); - - for (Map.Entry e : card.getCounters().entrySet()) { - if (e.getValue() >= c && (ctr.equals("ANY") || e.getKey().equals(CounterType.getType(ctr)))) { - result.ct = e.getKey(); - break; - } - } - return result; - } } } - return null; + + // if table is empty, than no counter was removed + return table.isEmpty() ? null : PaymentDecision.counters(table); } @Override @@ -843,7 +884,7 @@ public class AiCostDecision extends CostDecisionMakerBase { } } } else if (sVar.equals("Count$xPaid")) { - c = AbilityUtils.calculateAmount(source, "PayX", null); + c = AbilityUtils.calculateAmount(source, "PayX", ability); } else { c = AbilityUtils.calculateAmount(source, amount, ability); } @@ -898,7 +939,7 @@ public class AiCostDecision extends CostDecisionMakerBase { System.out.println("Couldn't find a valid card to untap for: " + source.getName()); return null; } - + return PaymentDecision.card(list); } diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java index 29ca893d82f..8a8a4734bed 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java @@ -161,8 +161,6 @@ public class ComputerUtil { // Play higher costing spells first? final Cost cost = sa.getPayCosts(); - // Convert cost to CMC - // String totalMana = source.getSVar("PayX"); // + cost.getCMC() // Consider the costs here for relative "scoring" if (hasDiscardHandCost(cost)) { @@ -2809,7 +2807,17 @@ public class ComputerUtil { } // this countertypes has no effect - public static boolean isUselessCounter(CounterType type) { + public static boolean isUselessCounter(CounterType type, Card c) { + + // Quest counter on a card without MaxQuestEffect are useless + if (type.is(CounterEnumType.QUEST)) { + int e = 0; + if ( c.hasSVar("MaxQuestEffect")) { + e = Integer.parseInt(c.getSVar("MaxQuestEffect")); + } + return c.getCounters(type) > e; + } + return type.is(CounterEnumType.AWAKENING) || type.is(CounterEnumType.MANIFESTATION) || type.is(CounterEnumType.PETRIFICATION) || type.is(CounterEnumType.TRAINING); } diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java index ccf63277425..c5e428cd87d 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java @@ -19,6 +19,8 @@ import forge.game.zone.ZoneType; import forge.util.MyRandom; import forge.util.TextUtil; import forge.util.collect.FCollectionView; + +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import java.util.List; @@ -53,9 +55,6 @@ public class ComputerUtilCost { return true; } - public static boolean checkRemoveCounterCost(final Cost cost, final Card source) { - return checkRemoveCounterCost(cost, source, null); - } /** * Check remove counter cost. * @@ -69,6 +68,7 @@ public class ComputerUtilCost { if (cost == null) { return true; } + final AiCostDecision decision = new AiCostDecision(sa.getActivatingPlayer(), sa); for (final CostPart part : cost.getCostParts()) { if (part instanceof CostRemoveCounter) { final CostRemoveCounter remCounter = (CostRemoveCounter) part; @@ -88,17 +88,17 @@ public class ComputerUtilCost { // Remove X counters - set ChosenX to max possible value here, the SAs should correct that // value later as the AI decides what to do (in checkApiLogic / checkAiLogic) - if (sa != null && sa.hasSVar(remCounter.getAmount())) { + if (sa.hasSVar(remCounter.getAmount())) { final String sVar = sa.getSVar(remCounter.getAmount()); if (sVar.equals("XChoice") && !sa.hasSVar("ChosenX")) { sa.setSVar("ChosenX", String.valueOf(source.getCounters(type))); + } else if (sVar.equals("Count$xPaid") && sa.hasSVar("PayX")) { + sa.setSVar("PayX", Integer.toString(Math.min(Integer.valueOf(sa.getSVar("PayX")), source.getCounters(type)))); } } - // check the sa what the PaymentDecision is. // ignore Loyality abilities with Zero as Cost - if (sa != null && !type.is(CounterEnumType.LOYALTY)) { - final AiCostDecision decision = new AiCostDecision(sa.getActivatingPlayer(), sa); + if (!type.is(CounterEnumType.LOYALTY)) { PaymentDecision pay = decision.visit(remCounter); if (pay == null || pay.c <= 0) { return false; @@ -111,14 +111,10 @@ public class ComputerUtilCost { return false; } } else if (part instanceof CostRemoveAnyCounter) { - if (sa != null) { - final CostRemoveAnyCounter remCounter = (CostRemoveAnyCounter) part; + final CostRemoveAnyCounter remCounter = (CostRemoveAnyCounter) part; - PaymentDecision decision = new AiCostDecision(sa.getActivatingPlayer(), sa).visit(remCounter); - return decision != null; - } - - return false; + PaymentDecision pay = decision.visit(remCounter); + return pay != null; } } return true; @@ -677,4 +673,26 @@ public class ComputerUtilCost { } return false; } + + public static int getMaxXValue(SpellAbility sa, Player ai) { + final Cost abCost = sa.getPayCosts(); + if (abCost == null || !abCost.hasXInAnyCostPart()) { + return 0; + } + + Integer val = null; + + if (sa.costHasManaX()) { + val = ComputerUtilMana.determineLeftoverMana(sa, ai); + } + + if (sa.usesTargeting()) { + // if announce is used as min targets, check what the max possible number would be + if ("X".equals(sa.getTargetRestrictions().getMinTargets())) { + val = ObjectUtils.min(val, CardUtil.getValidCardsToTarget(sa.getTargetRestrictions(), sa).size()); + } + } + + return ObjectUtils.defaultIfNull(ObjectUtils.min(val, abCost.getMaxForNonManaX(sa, ai)), 0); + } } diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java index d0685de143f..cda5239a2b1 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java @@ -4,7 +4,6 @@ import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.*; import forge.ai.ability.AnimateAi; -import forge.card.CardStateName; import forge.card.ColorSet; import forge.card.MagicColor; import forge.card.mana.ManaAtom; @@ -119,10 +118,6 @@ public class ComputerUtilMana { return score; } - private static void sortManaAbilities(final Multimap manaAbilityMap) { - sortManaAbilities(manaAbilityMap, null); - } - private static void sortManaAbilities(final Multimap manaAbilityMap, final SpellAbility sa) { final Map manaCardMap = Maps.newHashMap(); final List orderedCards = Lists.newArrayList(); @@ -1194,11 +1189,11 @@ public class ComputerUtilMana { } else { // For Count$xPaid set PayX in the AFs then use that here // Else calculate it as appropriate. - final String xSvar = card.getSVar("X").startsWith("Count$xPaid") ? "PayX" : "X"; - if (!sa.getSVar(xSvar).isEmpty() || card.hasSVar(xSvar) || card.getState(CardStateName.Original).hasSVar(xSvar)) { - if (xSvar.equals("PayX") && (card.hasSVar(xSvar) || card.getState(CardStateName.Original).hasSVar(xSvar))) { + final String xSvar = sa.getSVar("X").startsWith("Count$xPaid") ? "PayX" : "X"; + if (sa.hasSVar(xSvar)) { + if (xSvar.equals("PayX")) { // X SVar may end up being an empty string when copying a spell with no cost (e.g. Jhoira Avatar) - String xValue = card.hasSVar(xSvar) ? card.getSVar(xSvar) : card.getState(CardStateName.Original).getSVar(xSvar); + String xValue = sa.getSVar(xSvar); manaToAdd = xValue.isEmpty() ? 0 : Integer.parseInt(xValue) * cost.getXcounter(); // X } else { manaToAdd = AbilityUtils.calculateAmount(card, xSvar, sa) * cost.getXcounter(); @@ -1206,9 +1201,7 @@ public class ComputerUtilMana { } } - String manaXColor = sa.getParam("XColor"); - ManaCostShard shardToGrow = ManaCostShard.parseNonGeneric(manaXColor == null ? "1" : manaXColor); - cost.increaseShard(shardToGrow, manaToAdd); + cost.increaseShard(ManaCostShard.parseNonGeneric(sa.getParamOrDefault("XColor", "1")), manaToAdd); if (!test) { sa.setXManaCostPaid(manaToAdd / cost.getXcounter()); diff --git a/forge-ai/src/main/java/forge/ai/SpecialCardAi.java b/forge-ai/src/main/java/forge/ai/SpecialCardAi.java index f5932462c3a..96978de7320 100644 --- a/forge-ai/src/main/java/forge/ai/SpecialCardAi.java +++ b/forge-ai/src/main/java/forge/ai/SpecialCardAi.java @@ -875,7 +875,7 @@ public class SpecialCardAi { tokenSize = 11; } - source.setSVar("PayX", Integer.toString(tokenSize)); + sa.setSVar("PayX", Integer.toString(tokenSize)); return true; } diff --git a/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java b/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java index 665e8881f4f..6b78b69b223 100644 --- a/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java +++ b/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java @@ -78,12 +78,6 @@ public abstract class SpellAbilityAi { } } - if (sa.hasParam("AITgtBeforeCostEval")) { - // Cost payment requires a valid target to be specified, e.g. Quillmane Baku, so run the API logic first - // to set the target, then decide on paying costs (slower, so only use for cards where it matters) - return checkApiLogic(ai, sa) && (cost == null || willPayCosts(ai, sa, cost, source)); - } - if (cost != null && !willPayCosts(ai, sa, cost, source)) { return false; } diff --git a/forge-ai/src/main/java/forge/ai/ability/AttachAi.java b/forge-ai/src/main/java/forge/ai/ability/AttachAi.java index 5473029db9f..09624b037d4 100644 --- a/forge-ai/src/main/java/forge/ai/ability/AttachAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/AttachAi.java @@ -93,7 +93,7 @@ public class AttachAi extends SpellAbilityAi { return false; } - if (abCost.getTotalMana().countX() > 0 && source.getSVar("X").equals("Count$xPaid")) { + if (abCost.getTotalMana().countX() > 0 && sa.getSVar("X").equals("Count$xPaid")) { // Set PayX here to maximum value. (Endless Scream and Venarian // Gold) final int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai); @@ -102,7 +102,7 @@ public class AttachAi extends SpellAbilityAi { return false; } - source.setSVar("PayX", Integer.toString(xPay)); + sa.setSVar("PayX", Integer.toString(xPay)); } if (ComputerUtilAbility.getAbilitySourceName(sa).equals("Chained to the Rocks")) { diff --git a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java index 12f5966d29e..3ca3777d814 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java @@ -339,10 +339,10 @@ public class ChangeZoneAi extends SpellAbilityAi { String type = sa.getParam("ChangeType"); if (type != null) { - if (type.contains("X") && source.getSVar("X").equals("Count$xPaid")) { + if (type.contains("X") && sa.getSVar("X").equals("Count$xPaid")) { // Set PayX here to maximum value. final int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(xPay)); + sa.setSVar("PayX", Integer.toString(xPay)); type = type.replace("X", Integer.toString(xPay)); } } @@ -384,11 +384,11 @@ public class ChangeZoneAi extends SpellAbilityAi { String num = sa.getParam("ChangeNum"); if (num != null) { - if (num.contains("X") && source.getSVar("X").equals("Count$xPaid")) { + if (num.contains("X") && sa.getSVar("X").equals("Count$xPaid")) { // Set PayX here to maximum value. int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai); xPay = Math.min(xPay, list.size()); - source.setSVar("PayX", Integer.toString(xPay)); + sa.setSVar("PayX", Integer.toString(xPay)); } } @@ -474,8 +474,6 @@ public class ChangeZoneAi extends SpellAbilityAi { // Fetching should occur fairly often as it helps cast more spells, and // have access to more mana - final Card source = sa.getHostCard(); - if (sa.hasParam("AILogic")) { if (sa.getParam("AILogic").equals("Never")) { /* @@ -496,10 +494,10 @@ public class ChangeZoneAi extends SpellAbilityAi { // this works for hidden because the mana is paid first. final String type = sa.getParam("ChangeType"); - if (type != null && type.contains("X") && source.getSVar("X").equals("Count$xPaid")) { + if (type != null && type.contains("X") && sa.getSVar("X").equals("Count$xPaid")) { // Set PayX here to maximum value. final int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(xPay)); + sa.setSVar("PayX", Integer.toString(xPay)); } Iterable pDefined; @@ -1830,7 +1828,7 @@ public class ChangeZoneAi extends SpellAbilityAi { int toPay = 0; boolean setPayX = false; - if (unlessCost.equals("X") && source.getSVar(unlessCost).equals("Count$xPaid")) { + if (unlessCost.equals("X") && sa.getSVar(unlessCost).equals("Count$xPaid")) { setPayX = true; toPay = ComputerUtilMana.determineLeftoverMana(sa, ai); } else { @@ -1846,7 +1844,7 @@ public class ChangeZoneAi extends SpellAbilityAi { } if (setPayX) { - source.setSVar("PayX", Integer.toString(toPay)); + sa.setSVar("PayX", Integer.toString(toPay)); } } } diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseColorAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseColorAi.java index e086a64803e..cefb6cfe3db 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChooseColorAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChooseColorAi.java @@ -44,7 +44,7 @@ public class ChooseColorAi extends SpellAbilityAi { } // Set PayX here to maximum value. int x = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(x)); + sa.setSVar("PayX", Integer.toString(x)); return true; } diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java index 0f2b2730321..7781490d425 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChooseSourceAi.java @@ -60,7 +60,7 @@ public class ChooseSourceAi extends SpellAbilityAi { return false; } - if (!ComputerUtilCost.checkRemoveCounterCost(abCost, source)) { + if (!ComputerUtilCost.checkRemoveCounterCost(abCost, source, sa)) { return false; } } diff --git a/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java b/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java index 7c14df50863..2e4a66fbcef 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java @@ -280,7 +280,7 @@ public class ControlGainAi extends SpellAbilityAi { @Override public boolean chkAIDrawback(SpellAbility sa, final Player ai) { final Game game = ai.getGame(); - if ((sa.getTargetRestrictions() == null) || !sa.getTargetRestrictions().doesTarget()) { + if (!sa.usesTargeting()) { if (sa.hasParam("AllValid")) { CardCollectionView tgtCards = CardLists.filterControlledBy(game.getCardsIn(ZoneType.Battlefield), ai.getOpponents()); tgtCards = AbilityUtils.filterListByType(tgtCards, sa.getParam("AllValid"), sa); diff --git a/forge-ai/src/main/java/forge/ai/ability/CounterAi.java b/forge-ai/src/main/java/forge/ai/ability/CounterAi.java index 41edaa0d49a..a60fbe69051 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CounterAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CounterAi.java @@ -103,7 +103,7 @@ public class CounterAi extends SpellAbilityAi { int toPay = 0; boolean setPayX = false; - if (unlessCost.equals("X") && source.getSVar(unlessCost).equals("Count$xPaid")) { + if (unlessCost.equals("X") && sa.getSVar(unlessCost).equals("Count$xPaid")) { setPayX = true; toPay = Math.min(ComputerUtilMana.determineLeftoverMana(sa, ai), usableManaSources + 1); } else { @@ -123,7 +123,7 @@ public class CounterAi extends SpellAbilityAi { } if (setPayX) { - source.setSVar("PayX", Integer.toString(toPay)); + sa.setSVar("PayX", Integer.toString(toPay)); } } @@ -267,7 +267,7 @@ public class CounterAi extends SpellAbilityAi { int toPay = 0; boolean setPayX = false; - if (unlessCost.equals("X") && source.getSVar(unlessCost).equals("Count$xPaid")) { + if (unlessCost.equals("X") && sa.getSVar(unlessCost).equals("Count$xPaid")) { setPayX = true; toPay = ComputerUtilMana.determineLeftoverMana(sa, ai); } else { @@ -289,7 +289,7 @@ public class CounterAi extends SpellAbilityAi { } if (setPayX) { - source.setSVar("PayX", Integer.toString(toPay)); + sa.setSVar("PayX", Integer.toString(toPay)); } } } diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java index e1d76e9c0db..8de73d6a071 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java @@ -338,7 +338,7 @@ public class CountersPutAi extends SpellAbilityAi { } if (amountStr.equals("X")) { - if (source.getSVar(amountStr).equals("Count$xPaid")) { + if (sa.getSVar(amountStr).equals("Count$xPaid")) { // By default, set PayX here to maximum value (used for most SAs of this type). amount = ComputerUtilMana.determineLeftoverMana(sa, ai); @@ -359,7 +359,7 @@ public class CountersPutAi extends SpellAbilityAi { } } - source.setSVar("PayX", Integer.toString(amount)); + sa.setSVar("PayX", Integer.toString(amount)); } else if ("ExiledCreatureFromGraveCMC".equals(logic)) { // e.g. Necropolis amount = Aggregates.max(CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES), CardPredicates.Accessors.fnGetCmc); @@ -698,8 +698,8 @@ public class CountersPutAi extends SpellAbilityAi { list = new CardCollection(AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa)); if (amountStr.equals("X") - && !source.hasSVar("PayX") /* SubAbility on something that already had set PayX, e.g. Endless One ETB counters */ - && ((sa.hasParam(amountStr) && sa.getSVar(amountStr).equals("Count$xPaid")) || source.getSVar(amountStr).equals("Count$xPaid") )) { + && !sa.hasSVar("PayX") /* SubAbility on something that already had set PayX, e.g. Endless One ETB counters */ + && ((sa.hasParam(amountStr) && sa.getSVar(amountStr).equals("Count$xPaid")))) { // detect if there's more than one X in the cost (Hangarback Walker, Walking Ballista, etc.) SpellAbility testSa = sa; @@ -725,7 +725,7 @@ public class CountersPutAi extends SpellAbilityAi { // Account for the multiple X in cost if (countX > 1) { payX /= countX; } - source.setSVar("PayX", Integer.toString(payX)); + sa.setSVar("PayX", Integer.toString(payX)); } if (!mandatory) { @@ -1031,7 +1031,7 @@ public class CountersPutAi extends SpellAbilityAi { } } else { for (CounterType type : options) { - if (!ComputerUtil.isNegativeCounter(type, c) && !ComputerUtil.isUselessCounter(type)) { + if (!ComputerUtil.isNegativeCounter(type, c) && !ComputerUtil.isUselessCounter(type, c)) { return type; } } diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersPutAllAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersPutAllAi.java index 8c883637620..4fc300b6c1b 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersPutAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersPutAllAi.java @@ -82,10 +82,10 @@ public class CountersPutAllAi extends SpellAbilityAi { // TODO improve X value to don't overpay when extra mana won't do // anything more useful final int amount; - if (amountStr.equals("X") && source.getSVar(amountStr).equals("Count$xPaid")) { + if (amountStr.equals("X") && sa.getSVar(amountStr).equals("Count$xPaid")) { // Set PayX here to maximum value. amount = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(amount)); + sa.setSVar("PayX", Integer.toString(amount)); } else { amount = AbilityUtils.calculateAmount(sa.getHostCard(), amountStr, sa); } diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersPutOrRemoveAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersPutOrRemoveAi.java index a261270dec9..70e66e15c59 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersPutOrRemoveAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersPutOrRemoveAi.java @@ -157,7 +157,7 @@ public class CountersPutOrRemoveAi extends SpellAbilityAi { if (!ComputerUtil.isNegativeCounter(aType, best)) { sa.getTargets().add(best); return true; - } else if (!ComputerUtil.isUselessCounter(aType)) { + } else if (!ComputerUtil.isUselessCounter(aType, best)) { // whould remove positive counter if (best.getCounters(aType) <= amount) { sa.getTargets().add(best); diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java index 1d4737a83ea..8ce1b1a369c 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersRemoveAi.java @@ -143,7 +143,7 @@ public class CountersRemoveAi extends SpellAbilityAi { // variable amount for Hex Parasite int amount; boolean xPay = false; - if (amountStr.equals("X") && source.getSVar("X").equals("Count$xPaid")) { + if (amountStr.equals("X") && sa.getSVar("X").equals("Count$xPaid")) { final int manaLeft = ComputerUtilMana.determineLeftoverMana(sa, ai); if (manaLeft == 0) { @@ -167,7 +167,7 @@ public class CountersRemoveAi extends SpellAbilityAi { if (amount >= ice) { sa.getTargets().add(depth); if (xPay) { - source.setSVar("PayX", Integer.toString(ice)); + sa.setSVar("PayX", Integer.toString(ice)); } return true; } @@ -186,7 +186,7 @@ public class CountersRemoveAi extends SpellAbilityAi { Card best = ComputerUtilCard.getBestPlaneswalkerAI(planeswalkerList); sa.getTargets().add(best); if (xPay) { - source.setSVar("PayX", Integer.toString(best.getCurrentLoyalty())); + sa.setSVar("PayX", Integer.toString(best.getCurrentLoyalty())); } return true; } @@ -297,7 +297,7 @@ public class CountersRemoveAi extends SpellAbilityAi { int amount; boolean xPay = false; // Timecrafting has X R - if (amountStr.equals("X") && source.getSVar("X").equals("Count$xPaid")) { + if (amountStr.equals("X") && sa.getSVar("X").equals("Count$xPaid")) { final int manaLeft = ComputerUtilMana.determineLeftoverMana(sa, ai); if (manaLeft == 0) { @@ -317,7 +317,7 @@ public class CountersRemoveAi extends SpellAbilityAi { int timeCount = best.getCounters(CounterEnumType.TIME); sa.getTargets().add(best); if (xPay) { - source.setSVar("PayX", Integer.toString(timeCount)); + sa.setSVar("PayX", Integer.toString(timeCount)); } return true; } diff --git a/forge-ai/src/main/java/forge/ai/ability/DamageAllAi.java b/forge-ai/src/main/java/forge/ai/ability/DamageAllAi.java index 79e83ac65a4..15e5c05c1a9 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DamageAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DamageAllAi.java @@ -83,7 +83,7 @@ public class DamageAllAi extends SpellAbilityAi { if (best_x > 0) { if (sa.getSVar(damage).equals("Count$xPaid")) { - source.setSVar("PayX", Integer.toString(best_x)); + sa.setSVar("PayX", Integer.toString(best_x)); } if (damage.equals("ChosenX")) { source.setSVar("ChosenX", "Number$" + best_x); @@ -203,7 +203,7 @@ public class DamageAllAi extends SpellAbilityAi { if (damage.equals("X") && sa.getSVar(damage).equals("Count$xPaid")) { // Set PayX here to maximum value. dmg = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(dmg)); + sa.setSVar("PayX", Integer.toString(dmg)); } if (sa.hasParam("ValidPlayers")) { @@ -285,7 +285,7 @@ public class DamageAllAi extends SpellAbilityAi { if (damage.equals("X") && sa.getSVar(damage).equals("Count$xPaid")) { // Set PayX here to maximum value. dmg = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(dmg)); + sa.setSVar("PayX", Integer.toString(dmg)); } if (sa.hasParam("ValidPlayers")) { diff --git a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java index 92c213ca2e3..20bbb1a8e5a 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java @@ -12,7 +12,6 @@ import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; import forge.game.card.*; import forge.game.cost.Cost; -import forge.game.cost.CostPart; import forge.game.cost.CostPartMana; import forge.game.cost.CostRemoveCounter; import forge.game.keyword.Keyword; @@ -75,8 +74,8 @@ public class DamageDealAi extends DamageAiBase { } // Set PayX here to maximum value. - dmg = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(dmg)); + dmg = ComputerUtilCost.getMaxXValue(sa, ai); + sa.setSVar("PayX", Integer.toString(dmg)); } else if (sa.getSVar(damage).equals("Count$CardsInYourHand") && source.isInZone(ZoneType.Hand)) { dmg--; // the card will be spent casting the spell, so actual damage is 1 less } @@ -96,7 +95,7 @@ public class DamageDealAi extends DamageAiBase { if (damage.equals("X")) { if (sa.getSVar(damage).equals("Count$xPaid") || sourceName.equals("Crater's Claws")) { - dmg = ComputerUtilMana.determineLeftoverMana(sa, ai); + dmg = ComputerUtilCost.getMaxXValue(sa, ai); // Try not to waste spells like Blaze or Fireball on early targets, try to do more damage with them if possible if (ai.getController().isAI()) { @@ -113,7 +112,7 @@ public class DamageDealAi extends DamageAiBase { } // Set PayX here to maximum value. It will be adjusted later depending on the target. - source.setSVar("PayX", Integer.toString(dmg)); + sa.setSVar("PayX", Integer.toString(dmg)); } else if (sa.getSVar(damage).contains("InYourHand") && source.isInZone(ZoneType.Hand)) { dmg = CardFactoryUtil.xCount(source, sa.getSVar(damage)) - 1; // the card will be spent casting the spell, so actual damage is 1 less } else if (sa.getSVar(damage).equals("TargetedPlayer$CardsInHand")) { @@ -225,7 +224,7 @@ public class DamageDealAi extends DamageAiBase { return false; } - if (!ComputerUtilCost.checkRemoveCounterCost(abCost, source)) { + if (!ComputerUtilCost.checkRemoveCounterCost(abCost, source, sa)) { return false; } @@ -266,7 +265,7 @@ public class DamageDealAi extends DamageAiBase { } } - if ((damage.equals("X") && source.getSVar(damage).equals("Count$xPaid")) || + if ((damage.equals("X") && sa.getSVar(damage).equals("Count$xPaid")) || sourceName.equals("Crater's Claws")){ // If I can kill my target by paying less mana, do it if (sa.usesTargeting() && !sa.getTargets().isTargetingAnyPlayer() && !sa.hasParam("DividedAsYouChoose")) { @@ -281,25 +280,13 @@ public class DamageDealAi extends DamageAiBase { if (sourceName.equals("Crater's Claws") && ai.hasFerocious()) { actualPay = actualPay > 2 ? actualPay - 2 : 0; } - source.setSVar("PayX", Integer.toString(actualPay)); - } - } - - if ("XCountersDamage".equals(logic)) { - // Check to ensure that we have enough counters to remove per the defined PayX - for (CostPart part : sa.getPayCosts().getCostParts()) { - if (part instanceof CostRemoveCounter) { - if (source.getCounters(((CostRemoveCounter) part).counter) < Integer.valueOf(source.getSVar("PayX"))) { - return false; - } - break; - } + sa.setSVar("PayX", Integer.toString(actualPay)); } } if ("DiscardCMCX".equals(sa.getParam("AILogic"))) { - final int CMC = Integer.parseInt(source.getSVar("PayX")); - return !CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.hasCMC(CMC)).isEmpty(); + final int cmc = Integer.parseInt(sa.getSVar("PayX")); + return !CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.hasCMC(cmc)).isEmpty(); } return true; @@ -990,7 +977,7 @@ public class DamageDealAi extends DamageAiBase { if (damage.equals("X") && sa.getSVar(damage).equals("Count$xPaid")) { // Set PayX here to maximum value. dmg = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(dmg)); + sa.setSVar("PayX", Integer.toString(dmg)); } final TargetRestrictions tgt = sa.getTargetRestrictions(); @@ -1002,7 +989,7 @@ public class DamageDealAi extends DamageAiBase { return false; } - if (damage.equals("X") && source.getSVar(damage).equals("Count$xPaid") && !sa.hasParam("DividedAsYouChoose")) { + if (damage.equals("X") && sa.getSVar(damage).equals("Count$xPaid") && !sa.hasParam("DividedAsYouChoose")) { // If I can kill my target by paying less mana, do it int actualPay = 0; final boolean noPrevention = sa.hasParam("NoPrevention"); @@ -1018,7 +1005,7 @@ public class DamageDealAi extends DamageAiBase { } } - source.setSVar("PayX", Integer.toString(actualPay)); + sa.setSVar("PayX", Integer.toString(actualPay)); } } @@ -1078,7 +1065,7 @@ public class DamageDealAi extends DamageAiBase { saTgt.resetTargets(); saTgt.getTargets().add(tgtCreature != null && dmg < opponent.getLife() ? tgtCreature : opponent); - source.setSVar("PayX", Integer.toString(dmg)); + sa.setSVar("PayX", Integer.toString(dmg)); return true; } diff --git a/forge-ai/src/main/java/forge/ai/ability/DamagePreventAi.java b/forge-ai/src/main/java/forge/ai/ability/DamagePreventAi.java index 2a171dbbb07..6e5259f25cb 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DamagePreventAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DamagePreventAi.java @@ -46,7 +46,7 @@ public class DamagePreventAi extends SpellAbilityAi { return false; } - if (!ComputerUtilCost.checkRemoveCounterCost(cost, hostCard)) { + if (!ComputerUtilCost.checkRemoveCounterCost(cost, hostCard, sa)) { return false; } diff --git a/forge-ai/src/main/java/forge/ai/ability/DamagePreventAllAi.java b/forge-ai/src/main/java/forge/ai/ability/DamagePreventAllAi.java index f6f8b73f2e2..f62a7b51c25 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DamagePreventAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DamagePreventAllAi.java @@ -34,7 +34,7 @@ public class DamagePreventAllAi extends SpellAbilityAi { return false; } - if (!ComputerUtilCost.checkRemoveCounterCost(cost, hostCard)) { + if (!ComputerUtilCost.checkRemoveCounterCost(cost, hostCard, sa)) { return false; } diff --git a/forge-ai/src/main/java/forge/ai/ability/DebuffAi.java b/forge-ai/src/main/java/forge/ai/ability/DebuffAi.java index 3d7b045108f..b41018c9d35 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DebuffAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DebuffAi.java @@ -50,7 +50,7 @@ public class DebuffAi extends SpellAbilityAi { return false; } - if (!ComputerUtilCost.checkRemoveCounterCost(cost, source)) { + if (!ComputerUtilCost.checkRemoveCounterCost(cost, source, sa)) { return false; } @@ -67,7 +67,7 @@ public class DebuffAi extends SpellAbilityAi { } } - if (!sa.usesTargeting() || !sa.getTargetRestrictions().doesTarget()) { + if (!sa.usesTargeting()) { List cards = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa); @@ -93,7 +93,7 @@ public class DebuffAi extends SpellAbilityAi { @Override public boolean chkAIDrawback(SpellAbility sa, Player ai) { - if ((sa.getTargetRestrictions() == null) || !sa.getTargetRestrictions().doesTarget()) { + if (!sa.usesTargeting()) { // TODO - copied from AF_Pump.pumpDrawbackAI() - what should be // here? } else { diff --git a/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java b/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java index dc0093e7a90..33108116b0c 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java @@ -48,7 +48,7 @@ public class DestroyAi extends SpellAbilityAi { return false; } - hasXCost = abCost.getCostMana() != null && abCost.getCostMana().getAmountOfX() > 0; + hasXCost = sa.costHasManaX(); } if ("AtOpponentsCombatOrAfter".equals(sa.getParam("AILogic"))) { diff --git a/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java b/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java index ba3b9e45afd..9fbe5427ccf 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java @@ -80,10 +80,10 @@ public class DestroyAllAi extends SpellAbilityAi { valid = sa.getParam("ValidCards"); } - if (valid.contains("X") && source.getSVar("X").equals("Count$xPaid")) { + if (valid.contains("X") && sa.getSVar("X").equals("Count$xPaid")) { // Set PayX here to maximum value. final int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(xPay)); + sa.setSVar("PayX", Integer.toString(xPay)); valid = valid.replace("X", Integer.toString(xPay)); } diff --git a/forge-ai/src/main/java/forge/ai/ability/DigAi.java b/forge-ai/src/main/java/forge/ai/ability/DigAi.java index 822423e4f48..d7aaed7d3ab 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DigAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DigAi.java @@ -75,9 +75,9 @@ public class DigAi extends SpellAbilityAi { final String num = sa.getParam("DigNum"); final boolean payXLogic = sa.hasParam("AILogic") && sa.getParam("AILogic").startsWith("PayX"); - if (num != null && (num.equals("X") && host.getSVar(num).equals("Count$xPaid")) || payXLogic) { + if (num != null && (num.equals("X") && sa.getSVar(num).equals("Count$xPaid")) || payXLogic) { // By default, set PayX here to maximum value. - if (!(sa instanceof AbilitySub) || host.getSVar("PayX").equals("")) { + if (!(sa instanceof AbilitySub) || sa.getSVar("PayX").equals("")) { int manaToSave = 0; // Special logic that asks the AI to conserve a certain amount of mana when paying X @@ -89,7 +89,7 @@ public class DigAi extends SpellAbilityAi { if (numCards <= 0) { return false; } - host.setSVar("PayX", Integer.toString(numCards)); + sa.setSVar("PayX", Integer.toString(numCards)); } } diff --git a/forge-ai/src/main/java/forge/ai/ability/DigUntilAi.java b/forge-ai/src/main/java/forge/ai/ability/DigUntilAi.java index f18dc3c7784..5eb12be3a17 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DigUntilAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DigUntilAi.java @@ -76,14 +76,14 @@ public class DigUntilAi extends SpellAbilityAi { } final String num = sa.getParam("Amount"); - if ((num != null) && num.equals("X") && source.getSVar(num).equals("Count$xPaid")) { + if ((num != null) && num.equals("X") && sa.getSVar(num).equals("Count$xPaid")) { // Set PayX here to maximum value. - if (!(sa instanceof AbilitySub) || source.getSVar("PayX").equals("")) { + if (!(sa instanceof AbilitySub) || sa.getSVar("PayX").equals("")) { int numCards = ComputerUtilMana.determineLeftoverMana(sa, ai); if (numCards <= 0) { return false; } - source.setSVar("PayX", Integer.toString(numCards)); + sa.setSVar("PayX", Integer.toString(numCards)); } } diff --git a/forge-ai/src/main/java/forge/ai/ability/DiscardAi.java b/forge-ai/src/main/java/forge/ai/ability/DiscardAi.java index d7dad6b293d..8bac65be1b4 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DiscardAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DiscardAi.java @@ -41,7 +41,7 @@ public class DiscardAi extends SpellAbilityAi { return false; } - if (!ComputerUtilCost.checkRemoveCounterCost(abCost, source)) { + if (!ComputerUtilCost.checkRemoveCounterCost(abCost, source, sa)) { return false; } @@ -85,14 +85,14 @@ public class DiscardAi extends SpellAbilityAi { } if (sa.hasParam("NumCards")) { - if (sa.getParam("NumCards").equals("X") && source.getSVar("X").equals("Count$xPaid")) { + if (sa.getParam("NumCards").equals("X") && sa.getSVar("X").equals("Count$xPaid")) { // Set PayX here to maximum value. final int cardsToDiscard = Math.min(ComputerUtilMana.determineLeftoverMana(sa, ai), ai.getWeakestOpponent() .getCardsIn(ZoneType.Hand).size()); if (cardsToDiscard < 1) { return false; } - source.setSVar("PayX", Integer.toString(cardsToDiscard)); + sa.setSVar("PayX", Integer.toString(cardsToDiscard)); } else { if (AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("NumCards"), sa) < 1) { return false; diff --git a/forge-ai/src/main/java/forge/ai/ability/DrawAi.java b/forge-ai/src/main/java/forge/ai/ability/DrawAi.java index 4047d12ee77..579d731d625 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DrawAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DrawAi.java @@ -238,17 +238,17 @@ public class DrawAi extends SpellAbilityAi { boolean xPaid = false; final String num = sa.getParam("NumCards"); if (num != null && num.equals("X")) { - if (source.getSVar(num).equals("Count$xPaid")) { + if (sa.getSVar(num).equals("Count$xPaid")) { // Set PayX here to maximum value. - if (drawback && !source.getSVar("PayX").equals("")) { - numCards = Integer.parseInt(source.getSVar("PayX")); + if (drawback && !sa.getSVar("PayX").equals("")) { + numCards = Integer.parseInt(sa.getSVar("PayX")); } else { numCards = ComputerUtilMana.determineLeftoverMana(sa, ai); // try not to overdraw int safeDraw = Math.min(computerMaxHandSize - computerHandSize, computerLibrarySize - 3); if (sa.getHostCard().isInstant() || sa.getHostCard().isSorcery()) { safeDraw++; } // card will be spent numCards = Math.min(numCards, safeDraw); - source.setSVar("PayX", Integer.toString(numCards)); + sa.setSVar("PayX", Integer.toString(numCards)); assumeSafeX = true; } xPaid = true; @@ -340,7 +340,7 @@ public class DrawAi extends SpellAbilityAi { // for drawing and losing life if (numCards >= oppA.getLife()) { if (xPaid) { - source.setSVar("PayX", Integer.toString(oppA.getLife())); + sa.setSVar("PayX", Integer.toString(oppA.getLife())); } sa.getTargets().add(oppA); return true; @@ -400,7 +400,7 @@ public class DrawAi extends SpellAbilityAi { } if (xPaid) { - source.setSVar("PayX", Integer.toString(numCards)); + sa.setSVar("PayX", Integer.toString(numCards)); } } @@ -411,7 +411,7 @@ public class DrawAi extends SpellAbilityAi { if (sa.getHostCard().isInZone(ZoneType.Hand)) { numCards++; // the card will be spent } - source.setSVar("PayX", Integer.toString(numCards)); + sa.setSVar("PayX", Integer.toString(numCards)); } else { // Don't draw too many cards and then risk discarding // cards at EOT diff --git a/forge-ai/src/main/java/forge/ai/ability/LifeGainAi.java b/forge-ai/src/main/java/forge/ai/ability/LifeGainAi.java index 5ad2c283477..359490e75fd 100644 --- a/forge-ai/src/main/java/forge/ai/ability/LifeGainAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/LifeGainAi.java @@ -49,7 +49,7 @@ public class LifeGainAi extends SpellAbilityAi { return false; } - if (!ComputerUtilCost.checkRemoveCounterCost(cost, source)) { + if (!ComputerUtilCost.checkRemoveCounterCost(cost, source, sa)) { return false; } } else { @@ -125,10 +125,10 @@ public class LifeGainAi extends SpellAbilityAi { final String amountStr = sa.getParam("LifeAmount"); int lifeAmount = 0; boolean activateForCost = ComputerUtil.activateForCost(sa, ai); - if (amountStr.equals("X") && source.getSVar(amountStr).equals("Count$xPaid")) { + if (amountStr.equals("X") && sa.getSVar(amountStr).equals("Count$xPaid")) { // Set PayX here to maximum value. final int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(xPay)); + sa.setSVar("PayX", Integer.toString(xPay)); lifeAmount = xPay; } else { lifeAmount = AbilityUtils.calculateAmount(sa.getHostCard(), amountStr, sa); @@ -213,12 +213,11 @@ public class LifeGainAi extends SpellAbilityAi { } } - final Card source = sa.getHostCard(); final String amountStr = sa.getParam("LifeAmount"); - if (amountStr.equals("X") && source.getSVar(amountStr).equals("Count$xPaid")) { + if (amountStr.equals("X") && sa.getSVar(amountStr).equals("Count$xPaid")) { // Set PayX here to maximum value. final int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(xPay)); + sa.setSVar("PayX", Integer.toString(xPay)); } return true; diff --git a/forge-ai/src/main/java/forge/ai/ability/LifeLoseAi.java b/forge-ai/src/main/java/forge/ai/ability/LifeLoseAi.java index 23ee0a4712e..de4bf22b32d 100644 --- a/forge-ai/src/main/java/forge/ai/ability/LifeLoseAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/LifeLoseAi.java @@ -34,14 +34,14 @@ public class LifeLoseAi extends SpellAbilityAi { final Card source = sa.getHostCard(); final String amountStr = sa.getParam("LifeAmount"); int amount = 0; - if (amountStr.equals("X") && source.getSVar(amountStr).equals("Count$xPaid")) { + if (amountStr.equals("X") && sa.getSVar(amountStr).equals("Count$xPaid")) { // something already set PayX - if (source.hasSVar("PayX")) { - amount = Integer.parseInt(source.getSVar("PayX")); + if (sa.hasSVar("PayX")) { + amount = Integer.parseInt(sa.getSVar("PayX")); } else { // Set PayX here to maximum value. final int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(xPay)); + sa.setSVar("PayX", Integer.toString(xPay)); amount = xPay; } } else { @@ -72,10 +72,9 @@ public class LifeLoseAi extends SpellAbilityAi { final String amountStr = sa.getParam("LifeAmount"); int amount = 0; - if (amountStr.equals("X") && source.getSVar(amountStr).equals("Count$xPaid")) { + if (amountStr.equals("X") && sa.getSVar(amountStr).equals("Count$xPaid")) { // Set PayX here to maximum value. amount = ComputerUtilMana.determineLeftoverMana(sa, ai); - // source.setSVar("PayX", Integer.toString(amount)); } else { amount = AbilityUtils.calculateAmount(source, amountStr, sa); } @@ -101,10 +100,10 @@ public class LifeLoseAi extends SpellAbilityAi { final String amountStr = sa.getParam("LifeAmount"); int amount = 0; - if (amountStr.equals("X") && source.getSVar(amountStr).equals("Count$xPaid")) { + if (amountStr.equals("X") && sa.getSVar(amountStr).equals("Count$xPaid")) { // Set PayX here to maximum value. amount = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(amount)); + sa.setSVar("PayX", Integer.toString(amount)); } else { amount = AbilityUtils.calculateAmount(source, amountStr, sa); } @@ -172,10 +171,10 @@ public class LifeLoseAi extends SpellAbilityAi { final Card source = sa.getHostCard(); final String amountStr = sa.getParam("LifeAmount"); int amount = 0; - if (amountStr.equals("X") && source.getSVar(amountStr).equals("Count$xPaid")) { + if (amountStr.equals("X") && sa.getSVar(amountStr).equals("Count$xPaid")) { // Set PayX here to maximum value. final int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(xPay)); + sa.setSVar("PayX", Integer.toString(xPay)); amount = xPay; } else { amount = AbilityUtils.calculateAmount(source, amountStr, sa); diff --git a/forge-ai/src/main/java/forge/ai/ability/LifeSetAi.java b/forge-ai/src/main/java/forge/ai/ability/LifeSetAi.java index 2afc4b47137..d51395a7026 100644 --- a/forge-ai/src/main/java/forge/ai/ability/LifeSetAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/LifeSetAi.java @@ -16,8 +16,6 @@ public class LifeSetAi extends SpellAbilityAi { @Override protected boolean canPlayAI(Player ai, SpellAbility sa) { - // Ability_Cost abCost = sa.getPayCosts(); - final Card source = sa.getHostCard(); final int myLife = ai.getLife(); final Player opponent = ai.getWeakestOpponent(); final int hlife = opponent.getLife(); @@ -42,10 +40,10 @@ public class LifeSetAi extends SpellAbilityAi { // would be paid int amount; // we shouldn't have to worry too much about PayX for SetLife - if (amountStr.equals("X") && source.getSVar(amountStr).equals("Count$xPaid")) { + if (amountStr.equals("X") && sa.getSVar(amountStr).equals("Count$xPaid")) { // Set PayX here to maximum value. final int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(xPay)); + sa.setSVar("PayX", Integer.toString(xPay)); amount = xPay; } else { amount = AbilityUtils.calculateAmount(sa.getHostCard(), amountStr, sa); @@ -114,10 +112,10 @@ public class LifeSetAi extends SpellAbilityAi { final String amountStr = sa.getParam("LifeAmount"); int amount; - if (amountStr.equals("X") && source.getSVar(amountStr).equals("Count$xPaid")) { + if (amountStr.equals("X") && sa.getSVar(amountStr).equals("Count$xPaid")) { // Set PayX here to maximum value. final int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(xPay)); + sa.setSVar("PayX", Integer.toString(xPay)); amount = xPay; } else { amount = AbilityUtils.calculateAmount(sa.getHostCard(), amountStr, sa); diff --git a/forge-ai/src/main/java/forge/ai/ability/ManifestAi.java b/forge-ai/src/main/java/forge/ai/ability/ManifestAi.java index b3d205c4958..b6608c17988 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ManifestAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ManifestAi.java @@ -80,7 +80,7 @@ public class ManifestAi extends SpellAbilityAi { // Handle either Manifest X cards, or Manifest 1 card and give it X P1P1s // Set PayX here to maximum value. int x = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(x)); + sa.setSVar("PayX", Integer.toString(x)); if (x <= 0) { return false; } diff --git a/forge-ai/src/main/java/forge/ai/ability/MillAi.java b/forge-ai/src/main/java/forge/ai/ability/MillAi.java index 52f0e8cda25..a469cc108be 100644 --- a/forge-ai/src/main/java/forge/ai/ability/MillAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/MillAi.java @@ -75,7 +75,6 @@ public class MillAi extends SpellAbilityAi { * - check for Laboratory Maniac effect (needs to check for actual * effect due to possibility of "lose abilities" effect) */ - final Card source = sa.getHostCard(); if (ComputerUtil.preventRunAwayActivations(sa)) { return false; // prevents mill 0 infinite loop? } @@ -90,10 +89,10 @@ public class MillAi extends SpellAbilityAi { } if ((sa.getParam("NumCards").equals("X") || sa.getParam("NumCards").equals("Z")) - && source.getSVar("X").startsWith("Count$xPaid")) { + && sa.getSVar("X").startsWith("Count$xPaid")) { // Set PayX here to maximum value. final int cardsToDiscard = getNumToDiscard(ai, sa); - source.setSVar("PayX", Integer.toString(cardsToDiscard)); + sa.setSVar("PayX", Integer.toString(cardsToDiscard)); return cardsToDiscard > 0; } return true; @@ -182,11 +181,10 @@ public class MillAi extends SpellAbilityAi { return false; } - final Card source = sa.getHostCard(); - if (sa.getParam("NumCards").equals("X") && source.getSVar("X").equals("Count$xPaid")) { + if (sa.getParam("NumCards").equals("X") && sa.getSVar("X").equals("Count$xPaid")) { // Set PayX here to maximum value. final int cardsToDiscard = getNumToDiscard(aiPlayer, sa); - source.setSVar("PayX", Integer.toString(cardsToDiscard)); + sa.setSVar("PayX", Integer.toString(cardsToDiscard)); } return true; diff --git a/forge-ai/src/main/java/forge/ai/ability/ProtectAi.java b/forge-ai/src/main/java/forge/ai/ability/ProtectAi.java index cf9ecdf6555..9557f3204eb 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ProtectAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ProtectAi.java @@ -164,7 +164,7 @@ public class ProtectAi extends SpellAbilityAi { @Override protected boolean checkApiLogic(final Player ai, final SpellAbility sa) { - if ((sa.getTargetRestrictions() == null) || !sa.getTargetRestrictions().doesTarget()) { + if (!sa.usesTargeting()) { final List cards = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa); if (cards.size() == 0) { return false; @@ -359,12 +359,7 @@ public class ProtectAi extends SpellAbilityAi { @Override public boolean chkAIDrawback(SpellAbility sa, Player ai) { - final Card host = sa.getHostCard(); - if ((sa.getTargetRestrictions() == null) || !sa.getTargetRestrictions().doesTarget()) { - if (host.isCreature()) { - // TODO - } - } else { + if (sa.usesTargeting()) { return protectTgtAI(ai, sa, false); } diff --git a/forge-ai/src/main/java/forge/ai/ability/ProtectAllAi.java b/forge-ai/src/main/java/forge/ai/ability/ProtectAllAi.java index 7fb827cd033..8e60b3d397c 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ProtectAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ProtectAllAi.java @@ -33,7 +33,7 @@ public class ProtectAllAi extends SpellAbilityAi { return false; } - if (!ComputerUtilCost.checkRemoveCounterCost(cost, hostCard)) { + if (!ComputerUtilCost.checkRemoveCounterCost(cost, hostCard, sa)) { return false; } diff --git a/forge-ai/src/main/java/forge/ai/ability/PumpAi.java b/forge-ai/src/main/java/forge/ai/ability/PumpAi.java index 9d4ec101c8e..2da1bfb5662 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PumpAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/PumpAi.java @@ -10,8 +10,6 @@ import forge.game.ability.ApiType; import forge.game.card.*; import forge.game.card.CardPredicates.Presets; import forge.game.cost.Cost; -import forge.game.cost.CostPart; -import forge.game.cost.CostRemoveCounter; import forge.game.cost.CostTapType; import forge.game.keyword.Keyword; import forge.game.phase.PhaseHandler; @@ -288,19 +286,19 @@ public class PumpAi extends PumpAiBase { } } - if (source.getSVar("X").equals("Count$xPaid")) { - source.setSVar("PayX", ""); + if (sa.getSVar("X").equals("Count$xPaid")) { + sa.setSVar("PayX", ""); } int defense; - if (numDefense.contains("X") && source.getSVar("X").equals("Count$xPaid")) { + if (numDefense.contains("X") && sa.getSVar("X").equals("Count$xPaid")) { // Set PayX here to maximum value. - int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai); + int xPay = ComputerUtilCost.getMaxXValue(sa, ai); if (sourceName.equals("Necropolis Fiend")) { xPay = Math.min(xPay, sa.getActivatingPlayer().getCardsIn(ZoneType.Graveyard).size()); sa.setSVar("X", Integer.toString(xPay)); } - source.setSVar("PayX", Integer.toString(xPay)); + sa.setSVar("PayX", Integer.toString(xPay)); defense = xPay; if (numDefense.equals("-X")) { defense = -xPay; @@ -313,13 +311,13 @@ public class PumpAi extends PumpAiBase { } int attack; - if (numAttack.contains("X") && source.getSVar("X").equals("Count$xPaid")) { + if (numAttack.contains("X") && sa.getSVar("X").equals("Count$xPaid")) { // Set PayX here to maximum value. - final String toPay = source.getSVar("PayX"); + final String toPay = sa.getSVar("PayX"); if (toPay.equals("")) { - final int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(xPay)); + final int xPay = ComputerUtilCost.getMaxXValue(sa, ai); + sa.setSVar("PayX", Integer.toString(xPay)); attack = xPay; } else { attack = Integer.parseInt(toPay); @@ -353,7 +351,7 @@ public class PumpAi extends PumpAiBase { } //Untargeted - if ((sa.getTargetRestrictions() == null) || !sa.getTargetRestrictions().doesTarget()) { + if (!sa.usesTargeting()) { final List cards = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa); if (cards.isEmpty()) { @@ -398,19 +396,10 @@ public class PumpAi extends PumpAiBase { return false; } - if ("DebuffForXCounters".equals(sa.getParam("AILogic")) && sa.getTargetCard() != null) { - // e.g. Skullmane Baku - CounterType ctrType = CounterType.get(CounterEnumType.KI); - for (CostPart part : sa.getPayCosts().getCostParts()) { - if (part instanceof CostRemoveCounter) { - ctrType = ((CostRemoveCounter)part).counter; - break; - } - } - + if (!sa.getSVar("PayX").isEmpty() && sa.getTargetCard() != null) { // Do not pay more counters than necessary to kill the targeted creature - int chosenX = Math.min(source.getCounters(ctrType), sa.getTargetCard().getNetToughness()); - sa.setSVar("ChosenX", String.valueOf(chosenX)); + int chosenX = Math.min(sa.getSVarInt("PayX"), sa.getTargetCard().getNetToughness()); + sa.setSVar("PayX", String.valueOf(chosenX)); } return true; @@ -573,12 +562,12 @@ public class PumpAi extends PumpAiBase { } } - while (sa.getTargets().size() < tgt.getMaxTargets(source, sa)) { + while (sa.canAddMoreTarget()) { Card t = null; // boolean goodt = false; if (list.isEmpty()) { - if (sa.getTargets().size() < tgt.getMinTargets(source, sa) || sa.getTargets().size() == 0) { + if (!sa.isMinTargetChosen() || sa.isZeroTargets()) { if (mandatory || ComputerUtil.activateForCost(sa, ai)) { return pumpMandatoryTarget(ai, sa); } @@ -678,28 +667,27 @@ public class PumpAi extends PumpAiBase { @Override protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) { - final Card source = sa.getHostCard(); final String numDefense = sa.hasParam("NumDef") ? sa.getParam("NumDef") : ""; final String numAttack = sa.hasParam("NumAtt") ? sa.getParam("NumAtt") : ""; int defense; - if (numDefense.contains("X") && source.getSVar("X").equals("Count$xPaid")) { + if (numDefense.contains("X") && sa.getSVar("X").equals("Count$xPaid")) { // Set PayX here to maximum value. - final int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(xPay)); + final int xPay = ComputerUtilCost.getMaxXValue(sa, ai); + sa.setSVar("PayX", Integer.toString(xPay)); defense = xPay; } else { defense = AbilityUtils.calculateAmount(sa.getHostCard(), numDefense, sa); } int attack; - if (numAttack.contains("X") && source.getSVar("X").equals("Count$xPaid")) { + if (numAttack.contains("X") && sa.getSVar("X").equals("Count$xPaid")) { // Set PayX here to maximum value. - final String toPay = source.getSVar("PayX"); + final String toPay = sa.getSVar("PayX"); if (toPay.equals("")) { - final int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(xPay)); + final int xPay = ComputerUtilCost.getMaxXValue(sa, ai); + sa.setSVar("PayX", Integer.toString(xPay)); attack = xPay; } else { attack = Integer.parseInt(toPay); @@ -708,7 +696,7 @@ public class PumpAi extends PumpAiBase { attack = AbilityUtils.calculateAmount(sa.getHostCard(), numAttack, sa); } - if (sa.getTargetRestrictions() == null) { + if (!sa.usesTargeting()) { if (mandatory) { return true; } @@ -749,28 +737,28 @@ public class PumpAi extends PumpAiBase { return false; } - int defense; - if (numDefense.contains("X") && source.getSVar("X").equals("Count$xPaid")) { - defense = Integer.parseInt(source.getSVar("PayX")); - } else { - defense = AbilityUtils.calculateAmount(sa.getHostCard(), numDefense, sa); - } - int attack; - if (numAttack.contains("X") && source.getSVar("X").equals("Count$xPaid")) { - if (source.getSVar("PayX").equals("")) { + if (numAttack.contains("X") && sa.getSVar("X").equals("Count$xPaid")) { + if (sa.getSVar("PayX").equals("")) { // X is not set yet - final int xPay = ComputerUtilMana.determineLeftoverMana(sa.getRootAbility(), ai); - source.setSVar("PayX", Integer.toString(xPay)); + final int xPay = ComputerUtilCost.getMaxXValue(sa, ai); + sa.setSVar("PayX", Integer.toString(xPay)); attack = xPay; } else { - attack = Integer.parseInt(source.getSVar("PayX")); + attack = Integer.parseInt(sa.getSVar("PayX")); } } else { attack = AbilityUtils.calculateAmount(sa.getHostCard(), numAttack, sa); } - if ((sa.getTargetRestrictions() == null) || !sa.getTargetRestrictions().doesTarget()) { + int defense; + if (numDefense.contains("X") && sa.getSVar("X").equals("Count$xPaid")) { + defense = Integer.parseInt(sa.getSVar("PayX")); + } else { + defense = AbilityUtils.calculateAmount(sa.getHostCard(), numDefense, sa); + } + + if (!sa.usesTargeting()) { if (source.isCreature()) { if (!source.hasKeyword(Keyword.INDESTRUCTIBLE) && source.getNetToughness() + defense <= source.getDamage()) { return false; diff --git a/forge-ai/src/main/java/forge/ai/ability/RepeatAi.java b/forge-ai/src/main/java/forge/ai/ability/RepeatAi.java index 7a37733b284..53be584b138 100644 --- a/forge-ai/src/main/java/forge/ai/ability/RepeatAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/RepeatAi.java @@ -2,22 +2,18 @@ package forge.ai.ability; import forge.ai.*; -import forge.game.card.Card; import forge.game.phase.PhaseType; import forge.game.player.Player; import forge.game.player.PlayerActionConfirmMode; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; public class RepeatAi extends SpellAbilityAi { @Override protected boolean canPlayAI(Player ai, SpellAbility sa) { - final Card source = sa.getHostCard(); - final TargetRestrictions tgt = sa.getTargetRestrictions(); final Player opp = ai.getWeakestOpponent(); - if (tgt != null) { + if (sa.usesTargeting()) { if (!opp.canBeTargetedBy(sa)) { return false; } @@ -31,7 +27,7 @@ public class RepeatAi extends SpellAbilityAi { } // Set PayX here to maximum value. final int max = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(max)); + sa.setSVar("PayX", Integer.toString(max)); return max > 0; } return true; diff --git a/forge-ai/src/main/java/forge/ai/ability/SacrificeAi.java b/forge-ai/src/main/java/forge/ai/ability/SacrificeAi.java index 78081283c46..18a2cf4e13e 100644 --- a/forge-ai/src/main/java/forge/ai/ability/SacrificeAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/SacrificeAi.java @@ -103,10 +103,10 @@ public class SacrificeAi extends SpellAbilityAi { return false; } - if (num.equals("X") && source.getSVar(num).equals("Count$xPaid")) { + if (num.equals("X") && sa.getSVar(num).equals("Count$xPaid")) { // Set PayX here to maximum value. final int xPay = Math.min(ComputerUtilMana.determineLeftoverMana(sa, ai), amount); - source.setSVar("PayX", Integer.toString(xPay)); + sa.setSVar("PayX", Integer.toString(xPay)); } final int half = (amount / 2) + (amount % 2); // Half of amount @@ -135,7 +135,7 @@ public class SacrificeAi extends SpellAbilityAi { final String num = sa.hasParam("Amount") ? sa.getParam("Amount") : "1"; int amount = AbilityUtils.calculateAmount(source, num, sa); - if (num.equals("X") && source.getSVar(num).equals("Count$xPaid")) { + if (num.equals("X") && sa.getSVar(num).equals("Count$xPaid")) { // Set PayX here to maximum value. amount = Math.min(ComputerUtilMana.determineLeftoverMana(sa, ai), amount); } diff --git a/forge-ai/src/main/java/forge/ai/ability/SacrificeAllAi.java b/forge-ai/src/main/java/forge/ai/ability/SacrificeAllAi.java index 8032c127eed..5f0e3de1931 100644 --- a/forge-ai/src/main/java/forge/ai/ability/SacrificeAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/SacrificeAllAi.java @@ -28,10 +28,10 @@ public class SacrificeAllAi extends SpellAbilityAi { valid = sa.getParam("ValidCards"); } - if (valid.contains("X") && source.getSVar("X").equals("Count$xPaid")) { + if (valid.contains("X") && sa.getSVar("X").equals("Count$xPaid")) { // Set PayX here to maximum value. final int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(xPay)); + sa.setSVar("PayX", Integer.toString(xPay)); valid = TextUtil.fastReplace(valid, "X", Integer.toString(xPay)); } diff --git a/forge-ai/src/main/java/forge/ai/ability/StoreSVarAi.java b/forge-ai/src/main/java/forge/ai/ability/StoreSVarAi.java index 2abada6610d..b7560a63b37 100644 --- a/forge-ai/src/main/java/forge/ai/ability/StoreSVarAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/StoreSVarAi.java @@ -32,7 +32,7 @@ public class StoreSVarAi extends SpellAbilityAi { // Set PayX here to half the remaining mana to allow for Main 2 and other combat shenanigans. final int xPay = ComputerUtilMana.determineLeftoverMana(sa, ai) / 2; if (xPay == 0) { return false; } - source.setSVar("PayX", Integer.toString(xPay)); + sa.setSVar("PayX", Integer.toString(xPay)); } final String logic = sa.getParam("AILogic"); diff --git a/forge-ai/src/main/java/forge/ai/ability/TapAi.java b/forge-ai/src/main/java/forge/ai/ability/TapAi.java index 54da422ee87..5bd753c2d4d 100644 --- a/forge-ai/src/main/java/forge/ai/ability/TapAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/TapAi.java @@ -3,18 +3,11 @@ package forge.ai.ability; import forge.ai.*; import forge.game.ability.AbilityUtils; import forge.game.card.Card; -import forge.game.card.CounterEnumType; -import forge.game.card.CounterType; import forge.game.cost.Cost; -import forge.game.cost.CostPart; -import forge.game.cost.CostRemoveCounter; import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; - -import java.util.List; public class TapAi extends TapAiBase { @Override @@ -48,7 +41,6 @@ public class TapAi extends TapAiBase { return false; } - final TargetRestrictions tgt = sa.getTargetRestrictions(); final Card source = sa.getHostCard(); final Cost abCost = sa.getPayCosts(); if (abCost != null) { @@ -57,32 +49,27 @@ public class TapAi extends TapAiBase { } } - if (tgt == null) { - final List defined = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa); - + if (!sa.usesTargeting()) { boolean bFlag = false; - for (final Card c : defined) { + for (final Card c : AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa)) { bFlag |= c.isUntapped(); } return bFlag; } else { - if ("TapForXCounters".equals(sa.getParam("AILogic"))) { - // e.g. Waxmane Baku - CounterType ctrType = CounterType.get(CounterEnumType.KI); - for (CostPart part : sa.getPayCosts().getCostParts()) { - if (part instanceof CostRemoveCounter) { - ctrType = ((CostRemoveCounter)part).counter; - break; - } - } + // X controls the minimum targets + if ("X".equals(sa.getTargetRestrictions().getMinTargets()) && sa.getSVar("X").equals("Count$xPaid")) { + // Set PayX here to maximum value. + int xPay = ComputerUtilCost.getMaxXValue(sa, ai); + sa.setSVar("PayX", Integer.toString(xPay)); - int numTargetable = Math.min(sa.getHostCard().getCounters(ctrType), ai.getOpponents().getCreaturesInPlay().size()); - sa.setSVar("ChosenX", String.valueOf(numTargetable)); + // TODO need to set XManaCostPaid for targets, maybe doesn't need PayX anymore? + sa.setXManaCostPaid(xPay); + // TODO since change of PayX. the shouldCastLessThanMax logic might be faulty } sa.resetTargets(); - return tapPrefTargeting(ai, source, tgt, sa, false); + return tapPrefTargeting(ai, source, sa, false); } } diff --git a/forge-ai/src/main/java/forge/ai/ability/TapAiBase.java b/forge-ai/src/main/java/forge/ai/ability/TapAiBase.java index 98734bc4f2f..e198d6f26ee 100644 --- a/forge-ai/src/main/java/forge/ai/ability/TapAiBase.java +++ b/forge-ai/src/main/java/forge/ai/ability/TapAiBase.java @@ -18,12 +18,11 @@ import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.game.zone.ZoneType; import java.util.List; -public abstract class TapAiBase extends SpellAbilityAi { +public abstract class TapAiBase extends SpellAbilityAi { /** *

@@ -41,21 +40,18 @@ public abstract class TapAiBase extends SpellAbilityAi { */ private boolean tapTargetList(final Player ai, final SpellAbility sa, final CardCollection tapList, final boolean mandatory) { final Card source = sa.getHostCard(); - final TargetRestrictions tgt = sa.getTargetRestrictions(); - for (final Card c : sa.getTargets().getTargetCards()) { - tapList.remove(c); - } + tapList.removeAll(sa.getTargets().getTargetCards()); if (tapList.isEmpty()) { return false; } - while (sa.getTargets().size() < tgt.getMaxTargets(source, sa)) { + while (sa.canAddMoreTarget()) { Card choice = null; - if (tapList.size() == 0) { - if (sa.getTargets().size() < tgt.getMinTargets(source, sa) || sa.getTargets().size() == 0) { + if (tapList.isEmpty()) { + if (!sa.isMinTargetChosen() || sa.isZeroTargets()) { if (!mandatory) { sa.resetTargets(); } @@ -76,7 +72,7 @@ public abstract class TapAiBase extends SpellAbilityAi { } if (choice == null) { // can't find anything left - if (sa.getTargets().size() < tgt.getMinTargets(sa.getHostCard(), sa) || sa.getTargets().size() == 0) { + if (!sa.isMinTargetChosen() || sa.isZeroTargets()) { if (!mandatory) { sa.resetTargets(); } @@ -111,11 +107,10 @@ public abstract class TapAiBase extends SpellAbilityAi { * a boolean. * @return a boolean. */ - protected boolean tapPrefTargeting(final Player ai, final Card source, final TargetRestrictions tgt, final SpellAbility sa, final boolean mandatory) { + protected boolean tapPrefTargeting(final Player ai, final Card source, final SpellAbility sa, final boolean mandatory) { final Player opp = ai.getWeakestOpponent(); final Game game = ai.getGame(); CardCollection tapList = CardLists.filterControlledBy(game.getCardsIn(ZoneType.Battlefield), ai.getOpponents()); - tapList = CardLists.getValidCards(tapList, tgt.getValidTgts(), source.getController(), source, sa); tapList = CardLists.getTargetableCards(tapList, sa); tapList = CardLists.filter(tapList, Presets.UNTAPPED); tapList = CardLists.filter(tapList, new Predicate() { @@ -136,10 +131,9 @@ public abstract class TapAiBase extends SpellAbilityAi { //use broader approach when the cost is a positive thing if (tapList.isEmpty() && ComputerUtil.activateForCost(sa, ai)) { - tapList = CardLists.filterControlledBy(game.getCardsIn(ZoneType.Battlefield), ai.getOpponents()); - tapList = CardLists.getValidCards(tapList, tgt.getValidTgts(), source.getController(), source, sa); + tapList = CardLists.filterControlledBy(game.getCardsIn(ZoneType.Battlefield), ai.getOpponents()); tapList = CardLists.getTargetableCards(tapList, sa); - tapList = CardLists.filter(tapList, new Predicate() { + tapList = CardLists.filter(tapList, new Predicate() { @Override public boolean apply(final Card c) { if (c.isCreature()) { @@ -162,15 +156,15 @@ public abstract class TapAiBase extends SpellAbilityAi { tapList.removeAll(toExclude); if (tapList.isEmpty()) { - return false; + return false; } boolean goodTargets = false; - while (sa.getTargets().size() < tgt.getMaxTargets(source, sa)) { + while (sa.canAddMoreTarget()) { Card choice = null; if (tapList.isEmpty()) { - if (sa.getTargets().size() < tgt.getMinTargets(source, sa) || sa.getTargets().size() == 0) { + if (!sa.isMinTargetChosen() || sa.isZeroTargets()) { if (!mandatory) { sa.resetTargets(); } @@ -186,8 +180,8 @@ public abstract class TapAiBase extends SpellAbilityAi { PhaseHandler phase = game.getPhaseHandler(); Card primeTarget = ComputerUtil.getKilledByTargeting(sa, tapList); if (primeTarget != null) { - choice = primeTarget; - goodTargets = true; + choice = primeTarget; + goodTargets = true; } else if (phase.isPlayerTurn(ai) && phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS)) { // Tap creatures possible blockers before combat during AI's turn. List attackers; @@ -231,7 +225,7 @@ public abstract class TapAiBase extends SpellAbilityAi { } if (choice == null) { // can't find anything left - if (sa.getTargets().size() < tgt.getMinTargets(sa.getHostCard(), sa) || sa.getTargets().size() == 0) { + if (!sa.isMinTargetChosen() || sa.isZeroTargets()) { if (!mandatory) { sa.resetTargets(); } @@ -265,19 +259,17 @@ public abstract class TapAiBase extends SpellAbilityAi { */ protected boolean tapUnpreferredTargeting(final Player ai, final SpellAbility sa, final boolean mandatory) { final Card source = sa.getHostCard(); - final TargetRestrictions tgt = sa.getTargetRestrictions(); final Game game = ai.getGame(); - CardCollection list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), source.getController(), source, sa); - list = CardLists.getTargetableCards(list, sa); - + CardCollection list = CardLists.getTargetableCards(game.getCardsIn(ZoneType.Battlefield), sa); + // try to tap anything controlled by the computer CardCollection tapList = CardLists.filterControlledBy(list, ai.getOpponents()); if (tapTargetList(ai, sa, tapList, mandatory)) { return true; } - if (sa.getTargets().size() >= tgt.getMinTargets(sa.getHostCard(), sa)) { + if (sa.isMinTargetChosen()) { return true; } @@ -296,7 +288,7 @@ public abstract class TapAiBase extends SpellAbilityAi { return true; } - if (sa.getTargets().size() >= tgt.getMinTargets(sa.getHostCard(), sa)) { + if (sa.isMinTargetChosen()) { return true; } @@ -308,11 +300,9 @@ public abstract class TapAiBase extends SpellAbilityAi { @Override protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) { - - final TargetRestrictions tgt = sa.getTargetRestrictions(); final Card source = sa.getHostCard(); - if (tgt == null) { + if (!sa.usesTargeting()) { if (mandatory) { return true; } @@ -322,7 +312,7 @@ public abstract class TapAiBase extends SpellAbilityAi { return true; } else { sa.resetTargets(); - if (tapPrefTargeting(ai, source, tgt, sa, mandatory)) { + if (tapPrefTargeting(ai, source, sa, mandatory)) { return true; } else if (mandatory) { // not enough preferred targets, but mandatory so keep going: @@ -335,17 +325,14 @@ public abstract class TapAiBase extends SpellAbilityAi { @Override public boolean chkAIDrawback(SpellAbility sa, Player ai) { - final TargetRestrictions tgt = sa.getTargetRestrictions(); final Card source = sa.getHostCard(); boolean randomReturn = true; - if (tgt == null) { - // either self or defined, either way should be fine - } else { + if (sa.usesTargeting()) { // target section, maybe pull this out? sa.resetTargets(); - if (!tapPrefTargeting(ai, source, tgt, sa, false)) { + if (!tapPrefTargeting(ai, source, sa, false)) { return false; } } diff --git a/forge-ai/src/main/java/forge/ai/ability/TapOrUntapAi.java b/forge-ai/src/main/java/forge/ai/ability/TapOrUntapAi.java index b2655c16ff5..949bb217141 100644 --- a/forge-ai/src/main/java/forge/ai/ability/TapOrUntapAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/TapOrUntapAi.java @@ -4,11 +4,8 @@ import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.util.MyRandom; -import java.util.List; - public class TapOrUntapAi extends TapAiBase { /* (non-Javadoc) @@ -16,19 +13,17 @@ public class TapOrUntapAi extends TapAiBase { */ @Override protected boolean canPlayAI(Player ai, SpellAbility sa) { - final TargetRestrictions tgt = sa.getTargetRestrictions(); final Card source = sa.getHostCard(); boolean randomReturn = MyRandom.getRandom().nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn()); - if (tgt == null) { + if (!sa.usesTargeting()) { // assume we are looking to tap human's stuff // TODO - check for things with untap abilities, and don't tap // those. - final List defined = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa); boolean bFlag = false; - for (final Card c : defined) { + for (final Card c : AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa)) { bFlag |= c.isUntapped(); } @@ -37,7 +32,7 @@ public class TapOrUntapAi extends TapAiBase { } } else { sa.resetTargets(); - if (!tapPrefTargeting(ai, source, tgt, sa, false)) { + if (!tapPrefTargeting(ai, source, sa, false)) { return false; } } diff --git a/forge-ai/src/main/java/forge/ai/ability/TokenAi.java b/forge-ai/src/main/java/forge/ai/ability/TokenAi.java index f6a62f567ef..7a6eb371c7c 100644 --- a/forge-ai/src/main/java/forge/ai/ability/TokenAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/TokenAi.java @@ -85,10 +85,10 @@ public class TokenAi extends SpellAbilityAi { if (source.getSVar("X").equals("Count$Converge")) { x = ComputerUtilMana.getConvergeCount(sa, ai); } - if (source.getSVar("X").equals("Count$xPaid")) { + if (sa.getSVar("X").equals("Count$xPaid")) { // Set PayX here to maximum value. x = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(x)); + sa.setSVar("PayX", Integer.toString(x)); } if (x <= 0) { return false; // 0 tokens or 0 toughness token(s) @@ -261,10 +261,10 @@ public class TokenAi extends SpellAbilityAi { if ("X".equals(tokenAmount) || "X".equals(tokenPower) || "X".equals(tokenToughness)) { int x = AbilityUtils.calculateAmount(source, tokenAmount, sa); - if (source.getSVar("X").equals("Count$xPaid")) { + if (sa.getSVar("X").equals("Count$xPaid")) { // Set PayX here to maximum value. x = ComputerUtilMana.determineLeftoverMana(sa, ai); - source.setSVar("PayX", Integer.toString(x)); + sa.setSVar("PayX", Integer.toString(x)); } if (x <= 0) { return false; diff --git a/forge-ai/src/main/java/forge/ai/ability/UnattachAllAi.java b/forge-ai/src/main/java/forge/ai/ability/UnattachAllAi.java index 4c877974ff2..a6dd8205ec6 100644 --- a/forge-ai/src/main/java/forge/ai/ability/UnattachAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/UnattachAllAi.java @@ -46,7 +46,7 @@ public class UnattachAllAi extends SpellAbilityAi { return false; } - source.setSVar("PayX", Integer.toString(xPay)); + sa.setSVar("PayX", Integer.toString(xPay)); } if (ai.getGame().getPhaseHandler().getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS) diff --git a/forge-ai/src/main/java/forge/ai/ability/UntapAi.java b/forge-ai/src/main/java/forge/ai/ability/UntapAi.java index 5145906e259..ecb45dd2ec8 100644 --- a/forge-ai/src/main/java/forge/ai/ability/UntapAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/UntapAi.java @@ -51,27 +51,24 @@ public class UntapAi extends SpellAbilityAi { @Override protected boolean checkApiLogic(Player ai, SpellAbility sa) { - final TargetRestrictions tgt = sa.getTargetRestrictions(); final Card source = sa.getHostCard(); if (ComputerUtil.preventRunAwayActivations(sa)) { return false; } - if (tgt == null) { + if (!sa.usesTargeting()) { final List pDefined = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa); return pDefined == null || !pDefined.get(0).isUntapped() || pDefined.get(0).getController() != ai; } else { - return untapPrefTargeting(ai, tgt, sa, false); + return untapPrefTargeting(ai, sa, false); } } @Override protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) { - final TargetRestrictions tgt = sa.getTargetRestrictions(); - - if (tgt == null) { + if (!sa.usesTargeting()) { if (mandatory) { return true; } @@ -80,7 +77,7 @@ public class UntapAi extends SpellAbilityAi { final List pDefined = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa); return pDefined == null || !pDefined.get(0).isUntapped() || pDefined.get(0).getController() != ai; } else { - if (untapPrefTargeting(ai, tgt, sa, mandatory)) { + if (untapPrefTargeting(ai, sa, mandatory)) { return true; } else if (mandatory) { // not enough preferred targets, but mandatory so keep going: @@ -100,7 +97,7 @@ public class UntapAi extends SpellAbilityAi { if (tgt == null) { // who cares if its already untapped, it's only a subability? } else { - if (!untapPrefTargeting(ai, tgt, sa, false)) { + if (!untapPrefTargeting(ai, sa, false)) { return false; } } @@ -113,15 +110,13 @@ public class UntapAi extends SpellAbilityAi { * untapPrefTargeting. *

* - * @param tgt - * a {@link forge.game.spellability.TargetRestrictions} object. * @param sa * a {@link forge.game.spellability.SpellAbility} object. * @param mandatory * a boolean. * @return a boolean. */ - private static boolean untapPrefTargeting(final Player ai, final TargetRestrictions tgt, final SpellAbility sa, final boolean mandatory) { + private static boolean untapPrefTargeting(final Player ai, final SpellAbility sa, final boolean mandatory) { final Card source = sa.getHostCard(); Player targetController = ai; @@ -131,7 +126,6 @@ public class UntapAi extends SpellAbilityAi { } CardCollection list = CardLists.getTargetableCards(targetController.getCardsIn(ZoneType.Battlefield), sa); - list = CardLists.getValidCards(list, tgt.getValidTgts(), source.getController(), source, sa); if (list.isEmpty()) { return false; @@ -175,7 +169,7 @@ public class UntapAi extends SpellAbilityAi { untapList.removeAll(toExclude); sa.resetTargets(); - while (sa.getTargets().size() < tgt.getMaxTargets(sa.getHostCard(), sa)) { + while (sa.canAddMoreTarget()) { Card choice = null; if (untapList.isEmpty()) { @@ -183,7 +177,7 @@ public class UntapAi extends SpellAbilityAi { if (sa.getSubAbility() != null && sa.getSubAbility().getApi() == ApiType.Animate && !list.isEmpty() && ai.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) { choice = ComputerUtilCard.getWorstPermanentAI(list, false, false, false, false); - } else if (sa.getTargets().size() < tgt.getMinTargets(sa.getHostCard(), sa) || sa.getTargets().size() == 0) { + } else if (!sa.isMinTargetChosen() || sa.isZeroTargets()) { sa.resetTargets(); return false; } else { @@ -204,7 +198,7 @@ public class UntapAi extends SpellAbilityAi { } if (choice == null) { // can't find anything left - if (sa.getTargets().size() < tgt.getMinTargets(sa.getHostCard(), sa) || sa.getTargets().size() == 0) { + if (!sa.isMinTargetChosen() || sa.isZeroTargets()) { sa.resetTargets(); return false; } else { diff --git a/forge-game/src/main/java/forge/game/ForgeScript.java b/forge-game/src/main/java/forge/game/ForgeScript.java index 06a3d41adee..49409689a32 100644 --- a/forge-game/src/main/java/forge/game/ForgeScript.java +++ b/forge-game/src/main/java/forge/game/ForgeScript.java @@ -126,7 +126,7 @@ public class ForgeScript { } else if (property.equals("nonManaAbility")) { return !sa.isManaAbility(); } else if (property.equals("withoutXCost")) { - return !sa.isXCost(); + return !sa.costHasManaX(); } else if (property.equals("Buyback")) { return sa.isBuyBackAbility(); } else if (property.equals("Cycling")) { diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index 853a1a35758..c41f9023d5c 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -227,12 +227,6 @@ public class GameAction { // ensure that any leftover keyword/type changes are cleared in the state view copied.updateStateForView(); - // Clean up temporary variables such as Sunburst value or announced PayX value - if (!(zoneTo.is(ZoneType.Stack) || zoneTo.is(ZoneType.Battlefield))) { - copied.clearTemporaryVars(); - } - - if (!suppress) { if (zoneFrom == null) { copied.getOwner().addInboundToken(copied); diff --git a/forge-game/src/main/java/forge/game/GameEntityCounterTable.java b/forge-game/src/main/java/forge/game/GameEntityCounterTable.java index d8c7b9b3403..6e8c7051552 100644 --- a/forge-game/src/main/java/forge/game/GameEntityCounterTable.java +++ b/forge-game/src/main/java/forge/game/GameEntityCounterTable.java @@ -31,15 +31,43 @@ public class GameEntityCounterTable extends ForwardingTable filterToRemove(GameEntity ge) { + Map result = Maps.newHashMap(); + if (!containsRow(ge)) { + result.putAll(ge.getCounters()); + return result; + } + Map alreadyRemoved = row(ge); + for (Map.Entry e : ge.getCounters().entrySet()) { + Integer rest = e.getValue() - (alreadyRemoved.containsKey(e.getKey()) ? alreadyRemoved.get(e.getKey()) : 0); + if (rest > 0) { + result.put(e.getKey(), rest); + } + } + return result; } public Map filterTable(CounterType type, String valid, Card host, SpellAbility sa) { Map result = Maps.newHashMap(); for (Map.Entry e : column(type).entrySet()) { - if (e.getKey().isValid(valid, host.getController(), host, sa)) { + if (e.getValue() > 0 && e.getKey().isValid(valid, host.getController(), host, sa)) { result.put(e.getKey(), e.getValue()); } } diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index a5180904bfb..1c88e8cb5f7 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -6410,17 +6410,6 @@ public class Card extends GameEntity implements Comparable, IHasSVars { return changed; } - public final void clearTemporaryVars() { - // Add cleanup for all variables that are set temporarily but that need - // to be restored to their original value if a card changes zones - - removeSVar("PayX"); // Temporary AI X announcement variable - removeSVar("IsCastFromPlayEffect"); // Temporary SVar indicating that the spell is cast indirectly via AF Play - setXManaCostPaidByColor(null); - setKickerMagnitude(0); - setPseudoMultiKickerMagnitude(0); - } - public final int getFinalChapterNr() { int n = 0; for (final Trigger t : getTriggers()) { diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java index 255fdd911dd..5f8630bb9f2 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -51,7 +51,6 @@ import forge.game.spellability.*; import forge.game.staticability.StaticAbility; import forge.game.trigger.Trigger; import forge.game.trigger.TriggerHandler; -import forge.game.zone.Zone; import forge.game.zone.ZoneType; import forge.util.Aggregates; import forge.util.Expressions; @@ -227,50 +226,6 @@ public class CardFactoryUtil { return AbilityFactory.getAbility(ab, sourceCard); } - /** - *

- * isTargetStillValid. - *

- * - * @param ability - * a {@link forge.game.spellability.SpellAbility} object. - * @param target - * a {@link forge.game.card.Card} object. - * @return a boolean. - */ - public static boolean isTargetStillValid(final SpellAbility ability, final Card target) { - Zone zone = target.getGame().getZoneOf(target); - if (zone == null) { - return false; // for tokens that disappeared - } - - final Card source = ability.getHostCard(); - final TargetRestrictions tgt = ability.getTargetRestrictions(); - if (tgt != null) { - // Reconfirm the Validity of a TgtValid, or if the Creature is still - // a Creature - if (tgt.doesTarget() - && !target.isValid(tgt.getValidTgts(), ability.getActivatingPlayer(), ability.getHostCard(), ability)) { - return false; - } - - // Check if the target is in the zone it needs to be in to be targeted - if (!tgt.getZone().contains(zone.getZoneType())) { - return false; - } - } - else { - // If an Aura's target is removed before it resolves, the Aura - // fizzles - if (source.isAura() && !target.isInZone(ZoneType.Battlefield)) { - return false; - } - } - - // Make sure it's still targetable as well - return ability.canTarget(target); - } - // does "target" have protection from "card"? /** *

diff --git a/forge-game/src/main/java/forge/game/card/CardProperty.java b/forge-game/src/main/java/forge/game/card/CardProperty.java index 13f747c7fd9..9d89c04eba1 100644 --- a/forge-game/src/main/java/forge/game/card/CardProperty.java +++ b/forge-game/src/main/java/forge/game/card/CardProperty.java @@ -1360,7 +1360,7 @@ public class CardProperty { } } else if (property.startsWith("hasXCost")) { SpellAbility sa1 = card.getFirstSpellAbility(); - if (sa1 != null && !sa1.isXCost()) { + if (sa1 != null && !sa1.costHasManaX()) { return false; } } else if (property.startsWith("suspended")) { diff --git a/forge-game/src/main/java/forge/game/card/CounterType.java b/forge-game/src/main/java/forge/game/card/CounterType.java index 0cf41244e4f..d64222b1691 100644 --- a/forge-game/src/main/java/forge/game/card/CounterType.java +++ b/forge-game/src/main/java/forge/game/card/CounterType.java @@ -45,6 +45,9 @@ public class CounterType implements Comparable, Serializable { } public static CounterType getType(String name) { + if ("Any".equalsIgnoreCase(name)) { + return null; + } try { return get(CounterEnumType.getType(name)); } catch (final IllegalArgumentException ex) { diff --git a/forge-game/src/main/java/forge/game/cost/Cost.java b/forge-game/src/main/java/forge/game/cost/Cost.java index 1c175b57428..bda38820815 100644 --- a/forge-game/src/main/java/forge/game/cost/Cost.java +++ b/forge-game/src/main/java/forge/game/cost/Cost.java @@ -6,12 +6,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import com.google.common.collect.Lists; @@ -42,7 +43,7 @@ import forge.util.TextUtil; *

* Cost class. *

- * + * * @author Forge * @version $Id$ */ @@ -105,7 +106,7 @@ public class Cost implements Serializable { /** * Gets the cost parts. - * + * * @return the cost parts */ public final List getCostParts() { @@ -127,11 +128,11 @@ public class Cost implements Serializable { } }); } - + /** * Get the cost parts, always including a mana cost part (which may be * zero). - * + * * @return the cost parts, possibly with an extra zero mana {@link * CostPartMana}. */ @@ -149,7 +150,7 @@ public class Cost implements Serializable { *

* isOnlyManaCost. *

- * + * * @return a boolean. */ public final boolean isOnlyManaCost() { @@ -167,7 +168,7 @@ public class Cost implements Serializable { *

* getTotalMana. *

- * + * * @return a {@link java.lang.String} object. */ public final ManaCost getTotalMana() { @@ -179,17 +180,17 @@ public class Cost implements Serializable { *

* isMandatory *

- * + * * @return boolean */ public final boolean isMandatory() { return this.isMandatory; } - + public final boolean isAbility() { return this.isAbility; } - + private Cost() { } @@ -400,9 +401,9 @@ public class Cost implements Serializable { } if (parse.startsWith("RemoveAnyCounter<")) { - final String[] splitStr = abCostParse(parse, 3); - final String description = splitStr.length > 2 ? splitStr[2] : null; - return new CostRemoveAnyCounter(splitStr[0], splitStr[1], description); + final String[] splitStr = abCostParse(parse, 4); + final String description = splitStr.length > 3 ? splitStr[3] : null; + return new CostRemoveAnyCounter(splitStr[0], CounterType.getType(splitStr[1]), splitStr[2], description); } if (parse.startsWith("Exile<")) { @@ -515,7 +516,7 @@ public class Cost implements Serializable { *

* abCostParse. *

- * + * * @param parse * a {@link java.lang.String} object. * @param numParse @@ -539,7 +540,7 @@ public class Cost implements Serializable { toRet.cacheTapCost(); return toRet; } - + public final Cost copyWithNoMana() { Cost toRet = new Cost(0); toRet.isAbility = this.isAbility; @@ -580,7 +581,7 @@ public class Cost implements Serializable { *

* refundPaidCost. *

- * + * * @param source * a {@link forge.game.card.Card} object. */ @@ -595,7 +596,7 @@ public class Cost implements Serializable { *

* isUndoable. *

- * + * * @return a boolean. */ public final boolean isUndoable() { @@ -612,7 +613,7 @@ public class Cost implements Serializable { *

* isReusuableResource. *

- * + * * @return a boolean. */ public final boolean isReusuableResource() { @@ -629,7 +630,7 @@ public class Cost implements Serializable { *

* isRenewableResource. *

- * + * * @return a boolean. */ public final boolean isRenewableResource() { @@ -646,7 +647,7 @@ public class Cost implements Serializable { *

* toString. *

- * + * * @return a {@link java.lang.String} object. */ @Override @@ -665,7 +666,7 @@ public class Cost implements Serializable { *

* toStringAlt. *

- * + * * @return a {@link java.lang.String} object. */ public final String toStringAlt() { @@ -676,7 +677,7 @@ public class Cost implements Serializable { *

* toSimpleString. *

- * + * * @return a {@link java.lang.String} object. */ public final String toSimpleString() { @@ -696,7 +697,7 @@ public class Cost implements Serializable { *

* spellToString. *

- * + * * @param bFlag * a boolean. * @return a {@link java.lang.String} object. @@ -747,7 +748,7 @@ public class Cost implements Serializable { *

* abilityToString. *

- * + * * @return a {@link java.lang.String} object. */ private String abilityToString() { @@ -788,7 +789,7 @@ public class Cost implements Serializable { /** * Convert amount type to words. - * + * * @param i * the i * @param amount @@ -809,7 +810,7 @@ public class Cost implements Serializable { *

* convertIntAndTypeToWords. *

- * + * * @param i * a int. * @param type @@ -848,7 +849,7 @@ public class Cost implements Serializable { /** * Convert amount type to words. - * + * * @param amount * the amount * @param type @@ -887,12 +888,12 @@ public class Cost implements Serializable { } else { costParts.add(0, new CostPartMana(oldManaCost.toManaCost(), r)); } - } else if (part instanceof CostDiscard || part instanceof CostTapType || + } else if (part instanceof CostDiscard || part instanceof CostTapType || part instanceof CostAddMana || part instanceof CostPayLife) { boolean alreadyAdded = false; for (final CostPart other : costParts) { if (other.getClass().equals(part.getClass()) && - part.getType().equals(other.getType()) && + part.getType().equals(other.getType()) && StringUtils.isNumeric(part.getAmount()) && StringUtils.isNumeric(other.getAmount())) { final String amount = String.valueOf(Integer.parseInt(part.getAmount()) + Integer.parseInt(other.getAmount())); @@ -959,5 +960,20 @@ public class Cost implements Serializable { return xCost; } + public Integer getMaxForNonManaX(final SpellAbility ability, final Player payer) { + Integer val = null; + for (CostPart p : getCostParts()) { + if (!p.getAmount().equals("X")) { + continue; + } + + val = ObjectUtils.min(val, p.getMaxAmountX(ability, payer)); + } + // extra 0 check + if (val != null && val <= 0 && hasManaCost() && !getCostMana().canXbe0()) { + val = null; + } + return val; + } public static final Cost Zero = new Cost(0); } diff --git a/forge-game/src/main/java/forge/game/cost/CostPart.java b/forge-game/src/main/java/forge/game/cost/CostPart.java index cea0bfb9ee8..41434860833 100644 --- a/forge-game/src/main/java/forge/game/cost/CostPart.java +++ b/forge-game/src/main/java/forge/game/cost/CostPart.java @@ -6,12 +6,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -49,7 +49,7 @@ public abstract class CostPart implements Comparable, Cloneable, Seria /** * Instantiates a new cost part. - * + * * @param amount * the amount * @param type @@ -67,16 +67,19 @@ public abstract class CostPart implements Comparable, Cloneable, Seria /** * Gets the amount. - * + * * @return the amount */ public final String getAmount() { return this.amount; } + public Integer getMaxAmountX(final SpellAbility ability, final Player payer) { + return null; + } /** * Gets the type. - * + * * @return the type */ public final String getType() { @@ -85,7 +88,7 @@ public abstract class CostPart implements Comparable, Cloneable, Seria /** * Gets the this. - * + * * @return the this */ public final boolean payCostFromSource() { @@ -94,7 +97,7 @@ public abstract class CostPart implements Comparable, Cloneable, Seria /** * Gets the type description. - * + * * @return the type description */ public final String getTypeDescription() { @@ -108,16 +111,16 @@ public abstract class CostPart implements Comparable, Cloneable, Seria /** * Checks if is reusable. - * + * * @return true, if is reusable */ public boolean isReusable() { return false; } - + /** * Checks if is renewable. - * + * * @return true, if is renewable */ public boolean isRenewable() { @@ -126,7 +129,7 @@ public abstract class CostPart implements Comparable, Cloneable, Seria /** * Checks if is undoable. - * + * * @return true, if is undoable */ public boolean isUndoable() { @@ -135,19 +138,19 @@ public abstract class CostPart implements Comparable, Cloneable, Seria /** * Convert amount. - * + * * @return the integer */ public final Integer convertAmount() { - return StringUtils.isNumeric(amount) ? Integer.parseInt(amount) : null; + return StringUtils.isNumeric(amount) ? Integer.parseInt(amount) : null; } /** * Can pay. - * + * * @param ability * the ability - * @param payer + * @param payer * @return true, if successful */ public abstract boolean canPay(SpellAbility ability, Player payer); @@ -156,7 +159,7 @@ public abstract class CostPart implements Comparable, Cloneable, Seria /* * (non-Javadoc) - * + * * @see java.lang.Object#toString() */ @Override @@ -164,7 +167,7 @@ public abstract class CostPart implements Comparable, Cloneable, Seria /** * Refund. Overridden in classes which know how to refund. - * + * * @param source * the source */ @@ -173,7 +176,7 @@ public abstract class CostPart implements Comparable, Cloneable, Seria /** * Sets the amount. - * + * * @param amountIn * the amount to set */ diff --git a/forge-game/src/main/java/forge/game/cost/CostPayEnergy.java b/forge-game/src/main/java/forge/game/cost/CostPayEnergy.java index 5402e5e6749..d683ae8b618 100644 --- a/forge-game/src/main/java/forge/game/cost/CostPayEnergy.java +++ b/forge-game/src/main/java/forge/game/cost/CostPayEnergy.java @@ -47,6 +47,10 @@ public class CostPayEnergy extends CostPart { @Override public int paymentOrder() { return 7; } + public Integer getMaxAmountX(final SpellAbility ability, final Player payer) { + return payer.getCounters(CounterEnumType.ENERGY); + } + /* * (non-Javadoc) * diff --git a/forge-game/src/main/java/forge/game/cost/CostRemoveAnyCounter.java b/forge-game/src/main/java/forge/game/cost/CostRemoveAnyCounter.java index 063a44ce224..7751acde500 100644 --- a/forge-game/src/main/java/forge/game/cost/CostRemoveAnyCounter.java +++ b/forge-game/src/main/java/forge/game/cost/CostRemoveAnyCounter.java @@ -6,30 +6,30 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package forge.game.cost; +import forge.game.GameEntity; import forge.game.ability.AbilityUtils; import forge.game.card.*; import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; -import forge.util.TextUtil; -import java.util.Map; +import com.google.common.collect.Table; /** * The Class CostRemoveAnyCounter. */ -public class CostRemoveAnyCounter extends CostPartWithList { +public class CostRemoveAnyCounter extends CostPart { /** * Serializables need a version ID. */ @@ -37,13 +37,8 @@ public class CostRemoveAnyCounter extends CostPartWithList { // RemoveAnyCounter // Power Conduit and Chisei, Heart of Oceans // Both cards have "Remove a counter from a permanent you control" - private CounterType counterType; - /** - * @param counterType the counterType to set - */ - public void setCounterType(CounterType counterType) { - this.counterType = counterType; - } + + public final CounterType counter; /** * Instantiates a new cost CostRemoveAnyCounter. @@ -51,33 +46,34 @@ public class CostRemoveAnyCounter extends CostPartWithList { * @param amount * the amount */ - public CostRemoveAnyCounter(final String amount, final String type, final String description) { + public CostRemoveAnyCounter(final String amount, final CounterType counter, final String type, final String description) { super(amount, type, description); + this.counter = counter; } @Override public int paymentOrder() { return 8; } - /* (non-Javadoc) - * @see forge.card.cost.CostPartWithList#getHashForList() - */ @Override - public String getHashForLKIList() { - return "CounterRemove"; - } - @Override - public String getHashForCardList() { - return "CounterRemoveCards"; + public Integer getMaxAmountX(final SpellAbility ability, final Player payer) { + + final Card source = ability.getHostCard(); + + CardCollectionView validCards = CardLists.getValidCards(payer.getCardsIn(ZoneType.Battlefield), this.getType().split(";"), payer, source, ability); + int allCounters = 0; + for (Card c : validCards) { + if (this.counter != null) { + allCounters += c.getCounters(this.counter); + } else { + for (Integer value : c.getCounters().values()) { + allCounters += value; + } + } + } + return allCounters; } - /** - * Gets the counter. - * - * @return the counter - */ - public CounterType getCounter() { - return this.counterType; - } + /* * (non-Javadoc) @@ -88,27 +84,7 @@ public class CostRemoveAnyCounter extends CostPartWithList { */ @Override public final boolean canPay(final SpellAbility ability, final Player payer) { - final Card source = ability.getHostCard(); - CardCollectionView validCards = payer.getCardsIn(ZoneType.Battlefield); - validCards = CardLists.getValidCards(validCards, this.getType().split(";"), payer, source, ability); - validCards = CardLists.filter(validCards, CardPredicates.hasCounters()); - if (validCards.isEmpty()) { - return false; - } - Integer i = this.convertAmount(); - - if (i == null) { - i = AbilityUtils.calculateAmount(source, this.getAmount(), ability); - } - int allCounters = 0; - for (Card c : validCards) { - final Map tgtCounters = c.getCounters(); - for (Integer value : tgtCounters.values()) { - allCounters += value; - } - } - - return i <= allCounters; + return AbilityUtils.calculateAmount(ability.getHostCard(), this.getAmount(), ability) <= getMaxAmountX(ability, payer); } /* @@ -120,39 +96,29 @@ public class CostRemoveAnyCounter extends CostPartWithList { public final String toString() { final StringBuilder sb = new StringBuilder(); + String counters = this.counter == null ? "counter" : this.counter.getName() + " counter"; + sb.append("Remove "); - sb.append(Cost.convertIntAndTypeToWords(this.convertAmount(), "counter")); + sb.append(Cost.convertAmountTypeToWords(this.convertAmount(), this.getAmount(), counters)); final String desc = this.getTypeDescription() == null ? this.getType() : this.getTypeDescription(); sb.append(" from ").append(desc); return sb.toString(); } - @Override - public boolean payAsDecided(Player ai, PaymentDecision decision, SpellAbility ability) { - final String amount = this.getAmount(); - final Card source = ability.getHostCard(); - Integer c = this.convertAmount(); - if (c == null) { - c = AbilityUtils.calculateAmount(source, amount, ability); - } - if (decision.cards.isEmpty()) { - System.err.println(TextUtil.concatWithSpace("Warning: payment decision array was empty when paying CostRemoveAnyCounter for" , ability.getDescription(), "from", ability.getHostCard().toString())); - return false; - } - Card valid = decision.cards.get(0); - counterType = decision.ct; - for (int i = 0; i < c; i++) { - executePayment(ability, valid); - } - source.setSVar("CostCountersRemoved", Integer.toString(c)); - return true; - } @Override - protected Card doPayment(SpellAbility ability, Card targetCard){ - targetCard.subtractCounter(this.getCounter(), 1); - return targetCard; + public boolean payAsDecided(Player ai, PaymentDecision decision, SpellAbility ability) { + final Card source = ability.getHostCard(); + + int removed = 0; + for (Table.Cell cell : decision.counterTable.cellSet()) { + removed += cell.getValue(); + cell.getRowKey().subtractCounter(cell.getColumnKey(), cell.getValue()); + } + + source.setSVar("CostCountersRemoved", Integer.toString(removed)); + return true; } public T accept(ICostVisitor visitor) { diff --git a/forge-game/src/main/java/forge/game/cost/CostRemoveCounter.java b/forge-game/src/main/java/forge/game/cost/CostRemoveCounter.java index d03d99cd45b..4788fdec31b 100644 --- a/forge-game/src/main/java/forge/game/cost/CostRemoveCounter.java +++ b/forge-game/src/main/java/forge/game/cost/CostRemoveCounter.java @@ -6,12 +6,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -19,6 +19,7 @@ package forge.game.cost; import com.google.common.collect.Lists; +import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CardLists; import forge.game.card.CounterEnumType; @@ -32,7 +33,7 @@ import java.util.List; /** * The Class CostRemoveCounter. */ -public class CostRemoveCounter extends CostPartWithList { +public class CostRemoveCounter extends CostPart { // SubCounter // Here are the cards that have RemoveCounter @@ -47,11 +48,10 @@ public class CostRemoveCounter extends CostPartWithList { private static final long serialVersionUID = 1L; public final CounterType counter; public final ZoneType zone; - private int cntRemoved; /** * Instantiates a new cost remove counter. - * + * * @param amount * the amount * @param counter @@ -73,11 +73,32 @@ public class CostRemoveCounter extends CostPartWithList { public int paymentOrder() { return 8; } @Override - public boolean isUndoable() { return true; } + public Integer getMaxAmountX(final SpellAbility ability, final Player payer) { + final CounterType cntrs = this.counter; + final Card source = ability.getHostCard(); + final String type = this.getType(); + if (this.payCostFromSource()) { + return source.getCounters(cntrs); + } else { + List typeList; + if (type.equals("OriginalHost")) { + typeList = Lists.newArrayList(ability.getOriginalHost()); + } else { + typeList = CardLists.getValidCards(payer.getCardsIn(this.zone), type.split(";"), payer, source, ability); + } + + // Single Target + int maxcount = 0; + for (Card c : typeList) { + maxcount = Math.max(maxcount, c.getCounters(cntrs)); + } + return maxcount; + } + } /* * (non-Javadoc) - * + * * @see forge.card.cost.CostPart#toString() */ @Override @@ -108,20 +129,7 @@ public class CostRemoveCounter extends CostPartWithList { /* * (non-Javadoc) - * - * @see forge.card.cost.CostPart#refund(forge.Card) - */ - @Override - public final void refund(final Card source) { - int refund = this.getCardList().size() == 1 ? this.cntRemoved : 1; // is wrong for Ooze Flux and Novijen Sages - for (final Card c : this.getCardList()) { - c.addCounter(this.counter, refund, source.getController(), false, false, null); - } - } - - /* - * (non-Javadoc) - * + * * @see * forge.card.cost.CostPart#canPay(forge.card.spellability.SpellAbility, * forge.Card, forge.Player, forge.card.cost.Cost) @@ -144,21 +152,10 @@ public class CostRemoveCounter extends CostPartWithList { typeList = CardLists.getValidCards(payer.getCardsIn(this.zone), type.split(";"), payer, source, ability); } if (amount != null) { - // TODO find better way than TypeDescription - if (this.getTypeDescription().equals("among creatures you control")) { - // remove X counters from among creatures you control - int totalCounters = 0; - for (Card c : typeList) { - totalCounters += c.getCounters(cntrs); - } - return totalCounters >= amount; - - } else { - // (default logic) remove X counters from a single permanent - for (Card c : typeList) { - if (c.getCounters(cntrs) - amount >= 0) { - return true; - } + // (default logic) remove X counters from a single permanent + for (Card c : typeList) { + if (c.getCounters(cntrs) - amount >= 0) { + return true; } } return false; @@ -171,32 +168,19 @@ public class CostRemoveCounter extends CostPartWithList { @Override public boolean payAsDecided(Player ai, PaymentDecision decision, SpellAbility ability) { Card source = ability.getHostCard(); - cntRemoved = decision.c; - for (final Card card : decision.cards) { - executePayment(ability, card); + + int removed = 0; + int toRemove = AbilityUtils.calculateAmount(source, getAmount(), ability); + // for this cost, the list should be only one + for (Card c : decision.cards) { + removed += toRemove; + c.subtractCounter(counter, toRemove); } - source.setSVar("CostCountersRemoved", Integer.toString(cntRemoved)); + + source.setSVar("CostCountersRemoved", Integer.toString(removed)); return true; } - @Override - protected Card doPayment(SpellAbility ability, Card targetCard){ - targetCard.subtractCounter(this.counter, cntRemoved); - return targetCard; - } - - /* (non-Javadoc) - * @see forge.card.cost.CostPartWithList#getHashForList() - */ - @Override - public String getHashForLKIList() { - return "CounterRemove"; - } - @Override - public String getHashForCardList() { - return "CounterRemoveCards"; - } - public T accept(ICostVisitor visitor) { return visitor.visit(this); } diff --git a/forge-game/src/main/java/forge/game/cost/PaymentDecision.java b/forge-game/src/main/java/forge/game/cost/PaymentDecision.java index 1cbfd22c138..e10ff87eb11 100644 --- a/forge-game/src/main/java/forge/game/cost/PaymentDecision.java +++ b/forge-game/src/main/java/forge/game/cost/PaymentDecision.java @@ -1,5 +1,6 @@ package forge.game.cost; +import forge.game.GameEntityCounterTable; import forge.game.card.Card; import forge.game.card.CardCollection; import forge.game.card.CounterType; @@ -10,72 +11,74 @@ import forge.util.TextUtil; import java.util.List; - public class PaymentDecision { public int c = 0; public String type; - public CounterType ct; public final CardCollection cards = new CardCollection(); public final List mana; public final List players; public final List sp; + // used for CostRemoveAnyCounter + public final GameEntityCounterTable counterTable; + public PaymentDecision(int cnt) { - this(null, null, null, null); + this(null, null, null, null, null); c = cnt; } private PaymentDecision(Iterable chosen, List manaProduced, List players, - List sp) { + List sp, GameEntityCounterTable counterTable) { if (chosen != null) { cards.addAll(chosen); } mana = manaProduced; this.players = players; this.sp = sp; + this.counterTable = counterTable; } - + private PaymentDecision(Card chosen) { - this(null, null, null, null); + this(null, null, null, null, null); cards.add(chosen); } - + public PaymentDecision(String choice) { - this(null, null, null, null); + this(null, null, null, null, null); type = choice; } public static PaymentDecision card(Card chosen) { return new PaymentDecision(chosen); } - + public static PaymentDecision card(Card chosen, int n) { PaymentDecision res = new PaymentDecision(chosen); res.c = n; return res; } - - + + public static PaymentDecision number(int c) { return new PaymentDecision(c); } public static PaymentDecision card(Iterable chosen) { - return new PaymentDecision(chosen, null, null, null); + return new PaymentDecision(chosen, null, null, null, null); } - + public static PaymentDecision card(Iterable chosen, int n) { - PaymentDecision res = new PaymentDecision(chosen, null, null, null); + PaymentDecision res = new PaymentDecision(chosen, null, null, null, null); res.c = n; return res; } - + public static PaymentDecision mana(List manas) { - return new PaymentDecision(null, manas, null, null); + return new PaymentDecision(null, manas, null, null, null); } - - + + /* (non-Javadoc) * @see java.lang.Object#toString() */ @@ -90,16 +93,14 @@ public class PaymentDecision { public static PaymentDecision players(List players) { // TODO Auto-generated method stub - return new PaymentDecision(null, null, players, null); - } - - public static PaymentDecision spellabilities(List sp) { - return new PaymentDecision(null, null, null, sp); + return new PaymentDecision(null, null, players, null, null); } - public static PaymentDecision card(Card selected, CounterType counterType) { - PaymentDecision res = card(selected); - res.ct = counterType; - return res; + public static PaymentDecision spellabilities(List sp) { + return new PaymentDecision(null, null, null, sp, null); + } + + public static PaymentDecision counters(GameEntityCounterTable counterTable) { + return new PaymentDecision(null, null, null, null, counterTable); } } diff --git a/forge-game/src/main/java/forge/game/spellability/AbilityActivated.java b/forge-game/src/main/java/forge/game/spellability/AbilityActivated.java index 050c551f62c..42d2e543a1b 100644 --- a/forge-game/src/main/java/forge/game/spellability/AbilityActivated.java +++ b/forge-game/src/main/java/forge/game/spellability/AbilityActivated.java @@ -64,9 +64,7 @@ public abstract class AbilityActivated extends SpellAbility implements Cloneable */ public AbilityActivated(final Card sourceCard, final Cost abCost, final TargetRestrictions tgt) { super(sourceCard, abCost); - if ((tgt != null) && tgt.doesTarget()) { - this.setTargetRestrictions(tgt); - } + this.setTargetRestrictions(tgt); } public boolean isActivatedAbility() { return true; } diff --git a/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java b/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java index 0b5ff4626ef..c867926a28b 100644 --- a/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java +++ b/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java @@ -348,7 +348,7 @@ public class AbilityManaPart implements java.io.Serializable { } if (restriction.startsWith("CostContainsX")) { - if (sa.isXCost()) { + if (sa.costHasManaX()) { return true; } continue; diff --git a/forge-game/src/main/java/forge/game/spellability/AbilityStatic.java b/forge-game/src/main/java/forge/game/spellability/AbilityStatic.java index bd14a4c8834..9c769c5e982 100644 --- a/forge-game/src/main/java/forge/game/spellability/AbilityStatic.java +++ b/forge-game/src/main/java/forge/game/spellability/AbilityStatic.java @@ -47,9 +47,7 @@ public abstract class AbilityStatic extends Ability implements Cloneable { public AbilityStatic(final Card sourceCard, final Cost abCost, final TargetRestrictions tgt) { super(sourceCard, abCost); - if ((tgt != null) && tgt.doesTarget()) { - this.setTargetRestrictions(tgt); - } + this.setTargetRestrictions(tgt); } @Override public boolean canPlay() { diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java index 227a81902ee..3fcba014cea 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -39,7 +39,6 @@ import forge.game.card.CardPredicates; import forge.game.card.CardZoneTable; import forge.game.cost.Cost; import forge.game.cost.CostPart; -import forge.game.cost.CostPartMana; import forge.game.cost.CostRemoveCounter; import forge.game.keyword.Keyword; import forge.game.mana.Mana; @@ -987,7 +986,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit final TargetRestrictions tr = getTargetRestrictions(); // Restriction related to this ability - if (tr != null) { + if (usesTargeting()) { if (tr.isUniqueTargets() && getUniqueTargets().contains(entity)) return false; @@ -1324,11 +1323,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit originalMapParams.put("Announce", announce + ";" + variable); } - public boolean isXCost() { - CostPartMana cm = payCosts != null ? getPayCosts().getCostMana() : null; - return cm != null && cm.getAmountOfX() > 0; - } - @Override public boolean canBeTargetedBy(SpellAbility sa) { return sa.canTargetSpellAbility(this); @@ -1406,14 +1400,22 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit return getTargetRestrictions().getMinTargets(hostCard, this) == 0 && getTargets().size() == 0; } + public boolean isMinTargetChosen() { + return getTargetRestrictions().isMinTargetsChosen(hostCard, this); + } + public boolean isMaxTargetChosen() { + return getTargetRestrictions().isMaxTargetsChosen(hostCard, this); + } + public boolean isTargetNumberValid() { if (!this.usesTargeting()) { return getTargets().isEmpty(); } - int minTargets = getTargetRestrictions().getMinTargets(hostCard, this); + if (!isMinTargetChosen()) { + return false; + } int maxTargets = getTargetRestrictions().getMaxTargets(hostCard, this); - int numTargets = getTargets().size(); if (maxTargets == 0 && getPayCosts().hasSpecificCostType(CostRemoveCounter.class) && hasSVar(getParam("TargetMax")) @@ -1426,7 +1428,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit maxTargets = Integer.parseInt(getHostCard().getSVar("CostCountersRemoved")); } - return minTargets <= numTargets && maxTargets >= numTargets; + return maxTargets >= getTargets().size(); } /** *

@@ -1667,8 +1669,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit SpellAbility currentAbility = this; final Card source = getHostCard(); do { - final TargetRestrictions tgt = currentAbility.getTargetRestrictions(); - if (tgt != null && tgt.doesTarget()) { + if (currentAbility.usesTargeting()) { currentAbility.clearTargets(); Player targetingPlayer; if (currentAbility.hasParam("TargetingPlayer")) { diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbilityCondition.java b/forge-game/src/main/java/forge/game/spellability/SpellAbilityCondition.java index 887c845d163..687d58ffdad 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbilityCondition.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbilityCondition.java @@ -24,7 +24,6 @@ import forge.game.GameType; import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CardCollectionView; -import forge.game.card.CardFactoryUtil; import forge.game.card.CardLists; import forge.game.card.CardUtil; import forge.game.phase.PhaseHandler; @@ -271,7 +270,7 @@ public class SpellAbilityCondition extends SpellAbilityVariables { if (this.isAllTargetsLegal()) { for (Card c : sa.getTargets().getTargetCards()) { - if (!CardFactoryUtil.isTargetStillValid(sa, c)) { + if (!sa.canTarget(c)) { return false; } } diff --git a/forge-game/src/main/java/forge/game/spellability/TargetRestrictions.java b/forge-game/src/main/java/forge/game/spellability/TargetRestrictions.java index 03ed158bcb6..d917a4058f9 100644 --- a/forge-game/src/main/java/forge/game/spellability/TargetRestrictions.java +++ b/forge-game/src/main/java/forge/game/spellability/TargetRestrictions.java @@ -49,7 +49,6 @@ public class TargetRestrictions { // Target Choices (which is specific for the StackInstance) // What this Object is restricted to targeting - private boolean tgtValid = false; private String[] originalValidTgts, validTgts; private String uiPrompt = ""; @@ -93,7 +92,6 @@ public class TargetRestrictions { * a {@link forge.game.spellability.TargetRestrictions} object. */ public TargetRestrictions(final TargetRestrictions target) { - this.tgtValid = true; this.uiPrompt = target.getVTSelection(); this.originalValidTgts = target.getValidTgts(); this.validTgts = this.originalValidTgts.clone(); @@ -129,7 +127,6 @@ public class TargetRestrictions { * a {@link java.lang.String} object. */ public TargetRestrictions(final String prompt, final String[] valid, final String min, final String max) { - this.tgtValid = true; this.uiPrompt = prompt; this.originalValidTgts = valid; this.validTgts = this.originalValidTgts.clone(); @@ -172,17 +169,6 @@ public class TargetRestrictions { this.maxTotalCMC = cmc; } - /** - *

- * doesTarget. - *

- * - * @return a boolean. - */ - public final boolean doesTarget() { - return this.tgtValid; - } - /** *

* getValidTgts. @@ -210,7 +196,7 @@ public class TargetRestrictions { * * @return the min targets */ - private final String getMinTargets() { + public final String getMinTargets() { return this.minTargets; } @@ -219,7 +205,7 @@ public class TargetRestrictions { * * @return the max targets */ - private final String getMaxTargets() { + public final String getMaxTargets() { return this.maxTargets; } @@ -278,8 +264,7 @@ public class TargetRestrictions { * @return a boolean. */ public final boolean isMaxTargetsChosen(final Card c, final SpellAbility sa) { - TargetChoices choice = sa.getTargets(); - return this.getMaxTargets(c, sa) == choice.size(); + return this.getMaxTargets(c, sa) == sa.getTargets().size(); } /** @@ -294,11 +279,11 @@ public class TargetRestrictions { * @return a boolean. */ public final boolean isMinTargetsChosen(final Card c, final SpellAbility sa) { - if (this.getMinTargets(c, sa) == 0) { + int min = getMinTargets(c, sa); + if (min == 0) { return true; } - TargetChoices choice = sa.getTargets(); - return this.getMinTargets(c, sa) <= choice.size(); + return min <= sa.getTargets().size(); } /** diff --git a/forge-game/src/main/java/forge/game/zone/MagicStack.java b/forge-game/src/main/java/forge/game/zone/MagicStack.java index ba22a8349e7..ba82b59502f 100644 --- a/forge-game/src/main/java/forge/game/zone/MagicStack.java +++ b/forge-game/src/main/java/forge/game/zone/MagicStack.java @@ -41,7 +41,6 @@ import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; import forge.game.card.Card; import forge.game.card.CardCollection; -import forge.game.card.CardFactoryUtil; import forge.game.card.CardUtil; import forge.game.event.EventValueChangeType; import forge.game.event.GameEventCardStatsChanged; @@ -593,7 +592,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable | Defined$ Self | NumAtt$ +Y | References$ X,Y | SpellDescription$ For each counter removed, CARDNAME gets +2/+0 until end of turn. -SVar:X:XChoice -#ChosenX SVar created by Cost payment -SVar:Y:SVar$ChosenX/Times.2 +SVar:X:Count$xPaid +SVar:Y:SVar$X/Times.2 AI:RemoveDeck:Random DeckHints:Type$Spirit|Arcane -SVar:Picture:http://www.wizards.com/global/images/magic/general/blademane_baku.jpg Oracle:Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Blademane Baku.\n{1}, Remove X ki counters from Blademane Baku: For each counter removed, Blademane Baku gets +2/+0 until end of turn. diff --git a/forge-gui/res/cardsfolder/c/chamber_sentry.txt b/forge-gui/res/cardsfolder/c/chamber_sentry.txt index 476a1d5715a..877e5f46cf3 100644 --- a/forge-gui/res/cardsfolder/c/chamber_sentry.txt +++ b/forge-gui/res/cardsfolder/c/chamber_sentry.txt @@ -4,7 +4,7 @@ Types:Artifact Creature Construct PT:0/0 K:etbCounter:P1P1:Y:no Condition:CARDNAME enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it. SVar:Y:Count$Converge -A:AB$ DealDamage | Announce$ X | Cost$ X T SubCounter | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ X | References$ X | AILogic$ XCountersDamage | SpellDescription$ CARDNAME deals X damage to any target. +A:AB$ DealDamage | Cost$ X T SubCounter | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ X | References$ X | SpellDescription$ CARDNAME deals X damage to any target. SVar:X:Count$xPaid A:AB$ ChangeZone | Cost$ W U B R G | Origin$ Graveyard | Destination$ Hand | ActivationZone$ Graveyard | SpellDescription$ Return CARDNAME from your graveyard to your hand. SVar:DiscardMe:1 diff --git a/forge-gui/res/cardsfolder/c/chisei_heart_of_oceans.txt b/forge-gui/res/cardsfolder/c/chisei_heart_of_oceans.txt index 3abbb3ec535..5e9cca07dfe 100644 --- a/forge-gui/res/cardsfolder/c/chisei_heart_of_oceans.txt +++ b/forge-gui/res/cardsfolder/c/chisei_heart_of_oceans.txt @@ -4,8 +4,8 @@ Types:Legendary Creature Spirit PT:4/4 K:Flying T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigSac | TriggerDescription$ At the beginning of your upkeep, sacrifice CARDNAME unless you remove a counter from a permanent you control. -SVar:TrigSac:DB$ Sacrifice | Defined$ Self | UnlessPayer$ You | UnlessCost$ RemoveAnyCounter<1/Permanent.YouCtrl/a permanent you control> +SVar:TrigSac:DB$ Sacrifice | Defined$ Self | UnlessPayer$ You | UnlessCost$ RemoveAnyCounter<1/Any/Permanent.YouCtrl/a permanent you control> DeckNeeds:Ability$Counters SVar:NeedsToPlay:Creature.YouCtrl+HasCounters -SVar:Picture:http://www.wizards.com/global/images/magic/general/chisei_heart_of_oceans.jpg +SVar:AIRemoveCounterCostPriority:ANY Oracle:Flying\nAt the beginning of your upkeep, sacrifice Chisei, Heart of Oceans unless you remove a counter from a permanent you control. diff --git a/forge-gui/res/cardsfolder/g/garruk_primal_hunter.txt b/forge-gui/res/cardsfolder/g/garruk_primal_hunter.txt index ec658e672f6..c6c8ab5f467 100644 --- a/forge-gui/res/cardsfolder/g/garruk_primal_hunter.txt +++ b/forge-gui/res/cardsfolder/g/garruk_primal_hunter.txt @@ -7,5 +7,4 @@ A:AB$ Draw | Cost$ SubCounter<3/LOYALTY> | Planeswalker$ True | Defined$ You | N SVar:X:Count$GreatestPower_Creature.YouCtrl A:AB$ Token | Cost$ SubCounter<6/LOYALTY> | Planeswalker$ True | Ultimate$ True | TokenAmount$ Y | TokenScript$ g_6_6_wurm | TokenOwner$ You | LegacyImage$ g 6 6 wurm m12 | SpellDescription$ Create a 6/6 green Wurm creature for each land you control. SVar:Y:Count$Valid Land.YouCtrl -SVar:Picture:http://www.wizards.com/global/images/magic/general/garruk_primal_hunter.jpg Oracle:[+1]: Create a 3/3 green Beast creature token.\n[-3]: Draw cards equal to the greatest power among creatures you control.\n[-6]: Create a 6/6 green Wurm creature for each land you control. diff --git a/forge-gui/res/cardsfolder/h/huatli_warrior_poet.txt b/forge-gui/res/cardsfolder/h/huatli_warrior_poet.txt index 9357d49fdb3..7977fee52a6 100644 --- a/forge-gui/res/cardsfolder/h/huatli_warrior_poet.txt +++ b/forge-gui/res/cardsfolder/h/huatli_warrior_poet.txt @@ -6,10 +6,9 @@ A:AB$ GainLife | Cost$ AddCounter<2/LOYALTY> | Planeswalker$ True | LifeAmount$ SVar:GreatestPow:Count$GreatestPower_Creature.YouCtrl A:AB$ Token | Cost$ AddCounter<0/LOYALTY> | Planeswalker$ True | TokenAmount$ 1 | TokenScript$ g_3_3_dinosaur_trample | TokenOwner$ You | SpellDescription$ Create a 3/3 green Dinosaur creature token with trample. # TODO: The AI never uses the Ultimate ability (most likely doesn't have the required logic for it) -A:AB$ DealDamage | Cost$ SubCounter | Announce$ X | XMaxLimit$ L | NumDmg$ X | References$ X,L | Planeswalker$ True | Ultimate$ True | ValidTgts$ Creature | TgtPrompt$ Select any number of target creatures | TargetMin$ 1 | TargetMax$ X | DividedAsYouChoose$ X | RememberDamaged$ True | SubAbility$ DBNoBlock | SpellDescription$ CARDNAME deals X damage divided as you choose among any number of target creatures. Creatures dealt damage this way can't block this turn. +A:AB$ DealDamage | Cost$ SubCounter | Announce$ X | NumDmg$ X | References$ X | Planeswalker$ True | Ultimate$ True | ValidTgts$ Creature | TgtPrompt$ Select any number of target creatures | TargetMin$ 1 | TargetMax$ X | DividedAsYouChoose$ X | RememberDamaged$ True | SubAbility$ DBNoBlock | SpellDescription$ CARDNAME deals X damage divided as you choose among any number of target creatures. Creatures dealt damage this way can't block this turn. SVar:DBNoBlock:DB$ Pump | KW$ HIDDEN CARDNAME can't block. | Defined$ Remembered | SubAbility$ DBCleanup | StackDescription$ Creatures dealt damage this way can't block this turn. SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:X:Count$XChoice -SVar:L:Count$CardCounters.LOYALTY DeckHas:Ability$LifeGain & Ability$Token Oracle:[+2]: You gain life equal to the greatest power among creatures you control.\n[0]: Create a 3/3 green Dinosaur creature token with trample.\n[-X]: Huatli, Warrior Poet deals X damage divided as you choose among any number of target creatures. Creatures dealt damage this way can't block this turn. diff --git a/forge-gui/res/cardsfolder/n/novijen_sages.txt b/forge-gui/res/cardsfolder/n/novijen_sages.txt index 1475498019e..2fa0c728d6e 100644 --- a/forge-gui/res/cardsfolder/n/novijen_sages.txt +++ b/forge-gui/res/cardsfolder/n/novijen_sages.txt @@ -3,8 +3,7 @@ ManaCost:4 U U Types:Creature Human Advisor Mutant PT:0/0 K:Graft:4 -A:AB$ Draw | Cost$ 1 SubCounter<2/P1P1/Creature/among creatures you control> | NumCards$ 1 | SpellDescription$ Draw a card. +A:AB$ Draw | Cost$ 1 RemoveAnyCounter<2/P1P1/Creature.YouCtrl/among creatures you control> | NumCards$ 1 | SpellDescription$ Draw a card. DeckNeeds:Ability$Counters DeckHas:Ability$Counters -SVar:Picture:http://www.wizards.com/global/images/magic/general/novijen_sages.jpg Oracle:Graft 4 (This creature enters the battlefield with four +1/+1 counters on it. Whenever another creature enters the battlefield, you may move a +1/+1 counter from this creature onto it.)\n{1}, Remove two +1/+1 counters from among creatures you control: Draw a card. diff --git a/forge-gui/res/cardsfolder/o/ooze_flux.txt b/forge-gui/res/cardsfolder/o/ooze_flux.txt index 0bfc0039635..3e1161d798f 100644 --- a/forge-gui/res/cardsfolder/o/ooze_flux.txt +++ b/forge-gui/res/cardsfolder/o/ooze_flux.txt @@ -1,9 +1,8 @@ Name:Ooze Flux ManaCost:3 G Types:Enchantment -A:AB$ Token | Announce$ X | Cost$ XCantBe0 1 G SubCounter | TokenAmount$ 1 | TokenScript$ g_x_x_ooze | TokenOwner$ You | LegacyImage$ g x x ooze gtc | TokenPower$ X | TokenToughness$ X | SpellDescription$ Create an X/X green Ooze creature token, where X is the number of +1/+1 counters removed this way. +A:AB$ Token | Cost$ XCantBe0 1 G RemoveAnyCounter | TokenAmount$ 1 | TokenScript$ g_x_x_ooze | TokenOwner$ You | LegacyImage$ g x x ooze gtc | TokenPower$ X | TokenToughness$ X | SpellDescription$ Create an X/X green Ooze creature token, where X is the number of +1/+1 counters removed this way. SVar:X:Count$xPaid AI:RemoveDeck:All DeckHints:Ability$Counters -SVar:Picture:http://www.wizards.com/global/images/magic/general/ooze_flux.jpg Oracle:{1}{G}, Remove one or more +1/+1 counters from among creatures you control: Create an X/X green Ooze creature token, where X is the number of +1/+1 counters removed this way. diff --git a/forge-gui/res/cardsfolder/p/petalmane_baku.txt b/forge-gui/res/cardsfolder/p/petalmane_baku.txt index 07bbc0fb932..78deace7265 100644 --- a/forge-gui/res/cardsfolder/p/petalmane_baku.txt +++ b/forge-gui/res/cardsfolder/p/petalmane_baku.txt @@ -3,11 +3,9 @@ ManaCost:1 G Types:Creature Spirit PT:1/2 T:Mode$ SpellCast | ValidCard$ Spirit,Arcane | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever you cast a Spirit or Arcane spell, you may put a ki counter on CARDNAME. -SVar:TrigPutCounter:DB$PutCounter | Defined$ Self | CounterType$ KI | CounterNum$ 1 -#ChosenX SVar created by Cost payment -A:AB$ Mana | Cost$ 1 SubCounter | Produced$ Any | Amount$ ChosenX | References$ X | AILogic$ ManaRitual | AINoRecursiveCheck$ True | SpellDescription$ Add X mana of any one color. -SVar:X:XChoice +SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ KI | CounterNum$ 1 +A:AB$ Mana | Cost$ 1 SubCounter | Produced$ Any | Amount$ X | References$ X | AILogic$ ManaRitual | AINoRecursiveCheck$ True | SpellDescription$ Add X mana of any one color. +SVar:X:Count$xPaid AI:RemoveDeck:Random DeckHints:Type$Spirit|Arcane -SVar:Picture:http://www.wizards.com/global/images/magic/general/petalmane_baku.jpg Oracle:Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Petalmane Baku.\n{1}, Remove X ki counters from Petalmane Baku: Add X mana of any one color. diff --git a/forge-gui/res/cardsfolder/p/power_conduit.txt b/forge-gui/res/cardsfolder/p/power_conduit.txt index 60fdd24c135..cc83bc5695e 100644 --- a/forge-gui/res/cardsfolder/p/power_conduit.txt +++ b/forge-gui/res/cardsfolder/p/power_conduit.txt @@ -1,9 +1,8 @@ Name:Power Conduit ManaCost:2 Types:Artifact -A:AB$ Charm | Cost$ T RemoveAnyCounter<1/Permanent.YouCtrl/a permanent you control> | Choices$ ConduitCharge,ConduitP1P1 | Defined$ You +A:AB$ Charm | Cost$ T RemoveAnyCounter<1/Any/Permanent.YouCtrl/a permanent you control> | Choices$ ConduitCharge,ConduitP1P1 | Defined$ You SVar:ConduitCharge:DB$ PutCounter | ValidTgts$ Artifact | TgtPrompt$ Select target artifact | CounterType$ CHARGE | CounterNum$ 1 | SpellDescription$ Put a charge counter on target artifact. SVar:ConduitP1P1:DB$ PutCounter | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on target creature. SVar:AIRemoveCounterCostPriority:ANY -SVar:Picture:http://www.wizards.com/global/images/magic/general/power_conduit.jpg Oracle:{T}, Remove a counter from a permanent you control: Choose one —\n• Put a charge counter on target artifact.\n• Put a +1/+1 counter on target creature. diff --git a/forge-gui/res/cardsfolder/q/quillmane_baku.txt b/forge-gui/res/cardsfolder/q/quillmane_baku.txt index ddf79d3bf5e..3f9a9f7e786 100644 --- a/forge-gui/res/cardsfolder/q/quillmane_baku.txt +++ b/forge-gui/res/cardsfolder/q/quillmane_baku.txt @@ -3,10 +3,10 @@ ManaCost:4 U Types:Creature Spirit PT:3/3 T:Mode$ SpellCast | ValidCard$ Spirit,Arcane | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever you cast a Spirit or Arcane spell, you may put a ki counter on CARDNAME. -SVar:TrigPutCounter:DB$PutCounter | Defined$ Self | CounterType$ KI | CounterNum$ 1 -A:AB$ ChangeZone | Cost$ 1 T SubCounter | Origin$ Battlefield | Destination$ Hand | ValidTgts$ Creature | ChangeNum$ 1 | References$ X | AITgtBeforeCostEval$ True | SpellDescription$ Return target creature with converted mana cost X or less to its owner's hand. -SVar:X:Targeted$CardManaCost +SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ KI | CounterNum$ 1 +A:AB$ ChangeZone | Cost$ 1 T SubCounter | Origin$ Battlefield | Destination$ Hand | ValidTgts$ Creature.cmcLEX | ChangeNum$ 1 | References$ X | SpellDescription$ Return target creature with converted mana cost X or less to its owner's hand. +SVar:X:Count$xPaid AI:RemoveDeck:Random +DeckHints:Type$Spirit|Arcane # We'll need to improve the script at some stage, especially if we add Hunter of Eyeblights or Razorfin Abolisher. -SVar:Picture:http://www.wizards.com/global/images/magic/general/quillmane_baku.jpg Oracle:Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Quillmane Baku.\n{1}, {T}, Remove X ki counters from Quillmane Baku: Return target creature with converted mana cost X or less to its owner's hand. diff --git a/forge-gui/res/cardsfolder/r/retribution_of_the_ancients.txt b/forge-gui/res/cardsfolder/r/retribution_of_the_ancients.txt index 806ab4283aa..a78a1318b96 100644 --- a/forge-gui/res/cardsfolder/r/retribution_of_the_ancients.txt +++ b/forge-gui/res/cardsfolder/r/retribution_of_the_ancients.txt @@ -1,9 +1,8 @@ Name:Retribution of the Ancients ManaCost:B Types:Enchantment -A:AB$ Pump | Announce$ X | Cost$ B SubCounter | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -X | NumDef$ -X | References$ X | IsCurse$ True | SpellDescription$ Target creature gets -X/-X until end of turn. +A:AB$ Pump | Cost$ B RemoveAnyCounter | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -X | NumDef$ -X | References$ X | IsCurse$ True | SpellDescription$ Target creature gets -X/-X until end of turn. SVar:X:Count$xPaid AI:RemoveDeck:All DeckNeeds:Ability$Counters -SVar:Picture:http://www.wizards.com/global/images/magic/general/retribution_of_the_ancients.jpg Oracle:{B}, Remove X +1/+1 counters from among creatures you control: Target creature gets -X/-X until end of turn. diff --git a/forge-gui/res/cardsfolder/s/skullmane_baku.txt b/forge-gui/res/cardsfolder/s/skullmane_baku.txt index 7763a6af192..1dfa5d8e7de 100644 --- a/forge-gui/res/cardsfolder/s/skullmane_baku.txt +++ b/forge-gui/res/cardsfolder/s/skullmane_baku.txt @@ -3,11 +3,9 @@ ManaCost:3 B B Types:Creature Spirit PT:2/1 T:Mode$ SpellCast | ValidCard$ Spirit,Arcane | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever you cast a Spirit or Arcane spell, you may put a ki counter on CARDNAME. -SVar:TrigPutCounter:DB$PutCounter | Defined$ Self | CounterType$ KI | CounterNum$ 1 -#ChosenX SVar created by Cost payment -A:AB$ Pump | Cost$ 1 T SubCounter | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -ChosenX | NumDef$ -ChosenX | IsCurse$ True | AILogic$ DebuffForXCounters | References$ X | SpellDescription$ Target creature gets -X/-X until end of turn. -SVar:X:XChoice +SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ KI | CounterNum$ 1 +A:AB$ Pump | Cost$ 1 T SubCounter | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -X | NumDef$ -X | IsCurse$ True | References$ X | SpellDescription$ Target creature gets -X/-X until end of turn. +SVar:X:Count$xPaid AI:RemoveDeck:Random DeckHints:Type$Spirit|Arcane -SVar:Picture:http://www.wizards.com/global/images/magic/general/skullmane_baku.jpg Oracle:Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Skullmane Baku.\n{1}, {T}, Remove X ki counters from Skullmane Baku: Target creature gets -X/-X until end of turn. diff --git a/forge-gui/res/cardsfolder/s/soul_diviner.txt b/forge-gui/res/cardsfolder/s/soul_diviner.txt index ee5b4f516fa..d86e1c17296 100644 --- a/forge-gui/res/cardsfolder/s/soul_diviner.txt +++ b/forge-gui/res/cardsfolder/s/soul_diviner.txt @@ -2,6 +2,6 @@ Name:Soul Diviner ManaCost:U B Types:Creature Zombie Wizard PT:2/3 -A:AB$ Draw | Cost$ T RemoveAnyCounter<1/Card.Artifact;Card.Creature;Card.Land;Card.Planeswalker/artifact, creature, land or planeswalker> | NumCards$ 1 | SpellDescription$ Draw a card. +A:AB$ Draw | Cost$ T RemoveAnyCounter<1/Any/Card.Artifact;Card.Creature;Card.Land;Card.Planeswalker/artifact, creature, land or planeswalker> | NumCards$ 1 | SpellDescription$ Draw a card. AI:RemoveDeck:Random Oracle:{T}, Remove a counter from an artifact, creature, land, or planeswalker you control: Draw a card. diff --git a/forge-gui/res/cardsfolder/upcoming/tayam_luminous_enigma.txt b/forge-gui/res/cardsfolder/upcoming/tayam_luminous_enigma.txt new file mode 100644 index 00000000000..c4c5feea2fa --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/tayam_luminous_enigma.txt @@ -0,0 +1,12 @@ +Name:Tayam, Luminous Enigma +ManaCost:1 W B G +Types:Legendary Creature Nightmare Beast +PT:3/3 +K:ETBReplacement:Other:AddExtraCounter:Mandatory:Battlefield:Creature.Other+YouCtrl +SVar:AddExtraCounter:DB$ PutCounter | ETB$ True | Defined$ ReplacedCard | CounterType$ Vigilance | CounterNum$ 1 | SpellDescription$ Each other creature you control enters the battlefield with an additional vigilance counter on it. +A:AB$ Mill | Cost$ 3 RemoveAnyCounter<3/Any/Permanent.YouCtrl/among permanents you control> | NumCards$ 3 | Defined$ You | SubAbility$ DBChangeZone | StackDescription$ SpellDescription | SpellDescription$ Mill three cards, then return a permanent card with converted mana cost 3 or less from your graveyard to the battlefield. +SVar:DBChangeZone:DB$ ChangeZone | Hidden$ True | Mandatory$ True | ChangeType$ Permanent.YouOwn+cmcLE3 | ChangeNum$ 1 | Origin$ Graveyard | Destination$ Battlefield +DeckHas:Ability$Counters +SVar:AIRemoveCounterCostPriority:Vigilance +Oracle:Each other creature you control enters the battlefield with an additional vigilance counter on it.\n{3}, Remove three counters from among creatures you control: Mill three cards, then return a permanent card with converted mana cost 3 or less from your graveyard to the battlefield. + diff --git a/forge-gui/res/cardsfolder/w/waxmane_baku.txt b/forge-gui/res/cardsfolder/w/waxmane_baku.txt index 9a7f91d050b..0feb2634a46 100644 --- a/forge-gui/res/cardsfolder/w/waxmane_baku.txt +++ b/forge-gui/res/cardsfolder/w/waxmane_baku.txt @@ -3,10 +3,9 @@ ManaCost:2 W Types:Creature Spirit PT:2/2 T:Mode$ SpellCast | ValidCard$ Spirit,Arcane | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigPutCounter | TriggerDescription$ Whenever you cast a Spirit or Arcane spell, you may put a ki counter on CARDNAME. -SVar:TrigPutCounter:DB$PutCounter | Defined$ Self | CounterType$ KI | CounterNum$ 1 -A:AB$ Tap | Announce$ X | XMaxLimit$ Ki | Cost$ 1 SubCounter | CostDesc$ {1}, Remove X ki counters from CARDNAME: | TargetMin$ X | TargetMax$ X | ValidTgts$ Creature | IsCurse$ True | AILogic$ TapForXCounters | TgtPrompt$ Select X target creatures | References$ X,Ki | SpellDescription$ Tap X target creatures. -SVar:X:XChoice -SVar:Ki:Count$CardCounters.KI +SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ KI | CounterNum$ 1 +A:AB$ Tap | Cost$ 1 SubCounter | TargetMin$ X | TargetMax$ X | ValidTgts$ Creature | IsCurse$ True | TgtPrompt$ Select X target creatures | References$ X | SpellDescription$ Tap X target creatures. +SVar:X:Count$xPaid AI:RemoveDeck:Random DeckHints:Type$Spirit|Arcane Oracle:Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Waxmane Baku.\n{1}, Remove X ki counters from Waxmane Baku: Tap X target creatures. diff --git a/forge-gui/src/main/java/forge/player/HumanCostDecision.java b/forge-gui/src/main/java/forge/player/HumanCostDecision.java index 15c31774702..baf6bb7a188 100644 --- a/forge-gui/src/main/java/forge/player/HumanCostDecision.java +++ b/forge-gui/src/main/java/forge/player/HumanCostDecision.java @@ -3,18 +3,18 @@ package forge.player; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; + import forge.card.CardType; import forge.game.Game; import forge.game.GameEntity; +import forge.game.GameEntityCounterTable; import forge.game.GameEntityView; import forge.game.GameEntityViewMap; import forge.game.ability.AbilityUtils; @@ -527,7 +527,7 @@ public class HumanCostDecision extends CostDecisionMakerBase { if (c == null) { c = AbilityUtils.calculateAmount(source, amount, ability); } - + if (!player.getController().confirmPayment(cost, Localizer.getInstance().getMessage("lblDoYouWantFlipNCoinAction", String.valueOf(c)), ability)) { return null; } @@ -907,57 +907,59 @@ public class HumanCostDecision extends CostDecisionMakerBase { c = AbilityUtils.calculateAmount(source, cost.getAmount(), ability); } - CardCollectionView list = new CardCollection(player.getCardsIn(ZoneType.Battlefield)); - list = CardLists.getValidCards(list, type.split(";"), player, source, ability); + CardCollectionView list = CardLists.getValidCards(player.getCardsIn(ZoneType.Battlefield), type.split(";"), player, source, ability); + list = CardLists.filter(list, CardPredicates.hasCounters()); - - list = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(final Card card) { - return card.hasCounters(); - } - }); - final InputSelectCardsFromList inp = new InputSelectCardsFromList(controller, 1, 1, list, ability); - inp.setMessage(Localizer.getInstance().getMessage("lblSelectTargetCounter", cost.getDescriptiveType())); - inp.setCancelAllowed(false); + final InputSelectCardToRemoveCounter inp = new InputSelectCardToRemoveCounter(controller, c, cost, cost.counter, list, ability); + inp.setCancelAllowed(true); inp.showAndWait(); - final Card selected = inp.getFirstSelected(); - final Map tgtCounters = selected.getCounters(); - final List typeChoices = new ArrayList<>(); - for (final CounterType key : tgtCounters.keySet()) { - if (tgtCounters.get(key) > 0) { - typeChoices.add(key); - } + if (inp.hasCancelled()) { + return null; } - final String prompt = Localizer.getInstance().getMessage("lblSelectRemoveCounterType"); - cost.setCounterType(controller.getGui().one(prompt, typeChoices)); - - return PaymentDecision.card(selected, cost.getCounter()); + return PaymentDecision.counters(inp.getCounterTable()); } - public static final class InputSelectCardToRemoveCounter extends InputSelectManyBase { + public static final class InputSelectCardToRemoveCounter extends InputSelectManyBase { private static final long serialVersionUID = 2685832214519141903L; - private final Map cardsChosen; private final CounterType counterType; private final CardCollectionView validChoices; - public InputSelectCardToRemoveCounter(final PlayerControllerHuman controller, final int cntCounters, final CounterType cType, final CardCollectionView validCards, final SpellAbility sa) { + private final GameEntityCounterTable counterTable = new GameEntityCounterTable(); + + public InputSelectCardToRemoveCounter(final PlayerControllerHuman controller, final int cntCounters, final CostPart costPart, final CounterType cType, final CardCollectionView validCards, final SpellAbility sa) { super(controller, cntCounters, cntCounters, sa); this.validChoices = validCards; counterType = cType; - cardsChosen = cntCounters > 0 ? new HashMap<>() : null; + + setMessage(Localizer.getInstance().getMessage("lblRemoveNTargetCounterFromCardPayCostConfirm", "%d", counterType == null ? "any" : counterType.getName(), costPart.getDescriptiveType())); } @Override protected boolean onCardSelected(final Card c, final List otherCardsToSelect, final ITriggerEvent triggerEvent) { - if (!isValidChoice(c) || c.getCounters(counterType) <= getTimesSelected(c)) { + if (!isValidChoice(c)) { return false; } - final int tc = getTimesSelected(c); - cardsChosen.put(c, tc + 1); + CounterType cType = this.counterType; + if (cType == null) { + Map cmap = counterTable.filterToRemove(c); + + String prompt = Localizer.getInstance().getMessage("lblSelectCountersTypeToRemove"); + + cType = getController().chooseCounterType(Lists.newArrayList(cmap.keySet()), sa, prompt, null); + } + + if (cType == null) { + return false; + } + + if (c.getCounters(cType) <= counterTable.get(c, cType)) { + return false; + } + + counterTable.put(c, cType, 1); onSelectStateChanged(c, true); refresh(); @@ -966,9 +968,25 @@ public class HumanCostDecision extends CostDecisionMakerBase { @Override public String getActivateAction(final Card c) { - if (!isValidChoice(c) || c.getCounters(counterType) <= getTimesSelected(c)) { + if (!isValidChoice(c)) { return null; } + if (counterType != null) { + if (c.getCounters(counterType) <= counterTable.get(c, counterType)) { + return null; + } + } else { + boolean found = false; + for (Map.Entry e : c.getCounters().entrySet()) { + if (e.getValue() > counterTable.get(c, e.getKey())) { + found = true; + break; + } + } + if (!found) { + return null; + } + } return Localizer.getInstance().getMessage("lblRemoveCounterFromCard"); } @@ -992,9 +1010,11 @@ public class HumanCostDecision extends CostDecisionMakerBase { private int getDistibutedCounters() { int sum = 0; - for (final Entry kv : cardsChosen.entrySet()) { - sum += kv.getValue().intValue(); + + for (Integer v : this.counterTable.values()) { + sum += v; } + return sum; } @@ -1002,13 +1022,13 @@ public class HumanCostDecision extends CostDecisionMakerBase { return validChoices.contains(choice); } - public int getTimesSelected(final Card c) { - return cardsChosen.containsKey(c) ? cardsChosen.get(c).intValue() : 0; + public GameEntityCounterTable getCounterTable() { + return this.counterTable; } @Override - public Collection getSelected() { - return cardsChosen.keySet(); + public Collection getSelected() { + return counterTable.rowKeySet(); } } @@ -1063,45 +1083,28 @@ public class HumanCostDecision extends CostDecisionMakerBase { return PaymentDecision.card(ability.getOriginalHost(), cntRemoved >= 0 ? cntRemoved : maxCounters); } - final CardCollectionView validCards = CardLists.getValidCards(player.getCardsIn(cost.zone), type.split(";"), player, source, ability); - if (cost.zone.equals(ZoneType.Battlefield)) { - if (cntRemoved == 0) { - return PaymentDecision.card(source, 0); - } - - final InputSelectCardToRemoveCounter inp = new InputSelectCardToRemoveCounter(controller, cntRemoved, cost.counter, validCards, ability); - inp.setMessage(Localizer.getInstance().getMessage("lblRemoveNTargetCounterFromCardPayCostConfirm", "%d", cost.counter.getName(), cost.getDescriptiveType())); - inp.setCancelAllowed(true); - inp.showAndWait(); - if (inp.hasCancelled()) { - return null; - } - - // Have to hack here: remove all counters minus one, without firing any triggers, - // triggers will fire when last is removed by executePayment. - // They don't care how many were removed anyway - // int sum = 0; - for (final Card crd : inp.getSelected()) { - final int removed = inp.getTimesSelected(crd); - // sum += removed; - if (removed < 2) { - continue; - } - final int oldVal = crd.getCounters().get(cost.counter).intValue(); - crd.getCounters().put(cost.counter, Integer.valueOf(oldVal - removed + 1)); - } - return PaymentDecision.card(inp.getSelected(), 1); - } - - // Rift Elemental only - always removes 1 counter, so there will be no code for N counters. - GameEntityViewMap gameCacheSuspended = GameEntityView.getMap(CardLists.filter(validCards, CardPredicates.hasCounter(cost.counter))); - - final CardView cv = controller.getGui().oneOrNone(Localizer.getInstance().getMessage("lblRemoveCountersFromAInZoneCard", cost.zone.getTranslatedName()), gameCacheSuspended.getTrackableKeys()); - if (cv == null || !gameCacheSuspended.containsKey(cv)) { + CardCollectionView validCards = CardLists.getValidCards(player.getCardsIn(cost.zone), type.split(";"), player, source, ability); + // you can only select 1 card to remove N counters from + validCards = CardLists.filter(validCards, CardPredicates.hasCounter(cost.counter, cntRemoved)); + if (validCards.isEmpty()) { return null; } - return PaymentDecision.card(gameCacheSuspended.get(cv), c); + final InputSelectCardsFromList inp = new InputSelectCardsFromList(controller, 1, 1, validCards, ability); + inp.setMessage(Localizer.getInstance().getMessage("lblRemoveCountersFromAInZoneCard", cost.zone.getTranslatedName())); + inp.setCancelAllowed(true); + inp.showAndWait(); + + if (inp.hasCancelled()) { + return null; + } + + final Card selected = inp.getFirstSelected(); + if (selected == null) { + return null; + } + + return PaymentDecision.card(selected, cntRemoved); } @Override diff --git a/forge-gui/src/main/java/forge/player/HumanPlay.java b/forge-gui/src/main/java/forge/player/HumanPlay.java index 2cae915eb2d..5663e55fc40 100644 --- a/forge-gui/src/main/java/forge/player/HumanPlay.java +++ b/forge-gui/src/main/java/forge/player/HumanPlay.java @@ -1,6 +1,6 @@ package forge.player; -import com.google.common.base.Predicate; + import com.google.common.collect.Iterables; import forge.FThreads; import forge.card.mana.ManaCost; @@ -29,12 +29,10 @@ import forge.util.TextUtil; import forge.util.collect.FCollectionView; import forge.util.gui.SGuiChoose; import forge.util.Localizer; -import forge.util.CardTranslation; import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.List; -import java.util.Map; public class HumanPlay { @@ -362,74 +360,20 @@ public class HumanPlay { part.payAsDecided(p, pd, sourceAbility); } else if (part instanceof CostRemoveCounter) { - CounterType counterType = ((CostRemoveCounter) part).counter; - int amount = getAmountFromPartX(part, source, sourceAbility); + PaymentDecision pd = part.accept(hcd); - if (!part.canPay(sourceAbility, p)) { + if (pd == null) return false; - } - - if (!mandatory) { - if (!p.getController().confirmPayment(part, Localizer.getInstance().getMessage("lblDoYouWantRemoveNTargetTypeCounterFromCard", String.valueOf(amount), counterType.getName(), CardTranslation.getTranslatedName(source.getName())), sourceAbility)) { - return false; - } - } - - source.subtractCounter(counterType, amount); + else + part.payAsDecided(p, pd, sourceAbility); } else if (part instanceof CostRemoveAnyCounter) { - int amount = getAmountFromPartX(part, source, sourceAbility); - CardCollectionView list = p.getCardsIn(ZoneType.Battlefield); - int allCounters = 0; - for (Card c : list) { - final Map tgtCounters = c.getCounters(); - for (Integer value : tgtCounters.values()) { - allCounters += value; - } - } - if (allCounters < amount) { return false; } + PaymentDecision pd = part.accept(hcd); - if (!mandatory) { - if (!p.getController().confirmPayment(part, Localizer.getInstance().getMessage("lblDoYouWantRemoveCountersFromCard", part.getDescriptiveType()), sourceAbility)) { - return false; - } - } - - list = CardLists.getValidCards(list, part.getType().split(";"), p, source, sourceAbility); - while (amount > 0) { - final CounterType counterType; - list = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(final Card card) { - return card.hasCounters(); - } - }); - if (list.isEmpty()) { return false; } - InputSelectCardsFromList inp = new InputSelectCardsFromList(controller, 1, 1, list, sourceAbility); - inp.setMessage(Localizer.getInstance().getMessage("lblSelectRemoveCounterCard")); - inp.setCancelAllowed(true); - inp.showAndWait(); - if (inp.hasCancelled()) { - continue; - } - Card selected = inp.getFirstSelected(); - final Map tgtCounters = selected.getCounters(); - final List typeChoices = new ArrayList<>(); - for (CounterType key : tgtCounters.keySet()) { - if (tgtCounters.get(key) > 0) { - typeChoices.add(key); - } - } - if (typeChoices.size() > 1) { - String cprompt = Localizer.getInstance().getMessage("lblSelectRemoveCounterType"); - counterType = controller.getGui().one(cprompt, typeChoices); - } - else { - counterType = typeChoices.get(0); - } - selected.subtractCounter(counterType, 1); - amount--; - } + if (pd == null) + return false; + else + part.payAsDecided(p, pd, sourceAbility); } else if (part instanceof CostExile) { CostExile costExile = (CostExile) part; diff --git a/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java b/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java index 493512562a0..499532bc431 100644 --- a/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java +++ b/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java @@ -29,7 +29,6 @@ import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CardPlayOption; import forge.game.cost.Cost; -import forge.game.cost.CostPart; import forge.game.cost.CostPartMana; import forge.game.cost.CostPayment; import forge.game.keyword.KeywordInterface; @@ -256,16 +255,7 @@ public class HumanPlaySpellAbility { } if (needX && manaCost != null) { - boolean xInCost = manaCost.getAmountOfX() > 0; - if (!xInCost) { - for (final CostPart part : cost.getCostParts()) { - if (part.getAmount().equals("X")) { - xInCost = true; - break; - } - } - } - if (xInCost) { + if (cost.hasXInAnyCostPart()) { final String sVar = ability.getSVar("X"); //only prompt for new X value if card doesn't determine it another way if ("Count$xPaid".equals(sVar) || sVar.isEmpty()) { final Integer value = controller.announceRequirements(ability, "X", allowZero && manaCost.canXbe0()); diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index 1e1130d13ba..6ee56cc6811 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -321,8 +321,27 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont public Integer announceRequirements(final SpellAbility ability, final String announce, final boolean canChooseZero) { final int min = canChooseZero ? 0 : 1; - final int max = ability.hasParam("XMaxLimit") ? AbilityUtils.calculateAmount(ability.getHostCard(), - ability.getParam("XMaxLimit"), ability) : Integer.MAX_VALUE; + int max = Integer.MAX_VALUE; + + if ("X".equals(announce)) { + Cost cost = ability.getPayCosts(); + if (ability.hasParam("XMaxLimit")) { + max = Math.min(max, AbilityUtils.calculateAmount(ability.getHostCard(), ability.getParam("XMaxLimit"), ability)); + } + if (cost != null) { + Integer costX = cost.getMaxForNonManaX(ability, player); + if (costX != null) { + max = Math.min(max, min); + } + } + } + + if (ability.usesTargeting()) { + // if announce is used as min targets, check what the max possible number would be + if (announce.equals(ability.getTargetRestrictions().getMinTargets())) { + max = Math.min(max, CardUtil.getValidCardsToTarget(ability.getTargetRestrictions(), ability).size()); + } + } return getGui().getInteger(localizer.getMessage("lblChooseAnnounceForCard", announce, CardTranslation.getTranslatedName(ability.getHostCard().getName())) , min, max, min + 9); } diff --git a/forge-gui/src/main/java/forge/player/TargetSelection.java b/forge-gui/src/main/java/forge/player/TargetSelection.java index 3463c6e457d..f62b1a41e29 100644 --- a/forge-gui/src/main/java/forge/player/TargetSelection.java +++ b/forge-gui/src/main/java/forge/player/TargetSelection.java @@ -71,11 +71,10 @@ public class TargetSelection { } public final boolean chooseTargets(Integer numTargets) { - final TargetRestrictions tgt = getTgt(); - final boolean canTarget = tgt != null && tgt.doesTarget(); - if (!canTarget) { + if (!ability.usesTargeting()) { throw new RuntimeException("TargetSelection.chooseTargets called for ability that does not target - " + ability); } + final TargetRestrictions tgt = getTgt(); // Number of targets is explicitly set only if spell is being redirected (ex. Swerve or Redirect) final int minTargets = numTargets != null ? numTargets.intValue() : tgt.getMinTargets(ability.getHostCard(), ability); From 258bcbf99af7550a1d9ecc51f176fc8eb263fa48 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Wed, 23 Dec 2020 09:37:00 +0100 Subject: [PATCH 79/97] remove isXCost --- .../src/main/java/forge/game/trigger/WrappedAbility.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java b/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java index 92083daab65..4cf6c739e8d 100644 --- a/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java +++ b/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java @@ -308,11 +308,6 @@ public class WrappedAbility extends Ability { return sa.isSpell(); } - @Override - public boolean isXCost() { - return sa.isXCost(); - } - @Override public String getSVar(String name) { return sa.getSVar(name); From 2668ab068078901137f11d8725b34454899dffff Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Wed, 23 Dec 2020 20:08:39 +0800 Subject: [PATCH 80/97] Use LibGDX 1.9.10 for Compatibility --- forge-gui-android/pom.xml | 2 +- forge-gui-ios/pom.xml | 2 +- forge-gui-mobile-dev/pom.xml | 6 +++--- forge-gui-mobile/pom.xml | 4 ++-- forge-gui-mobile/src/forge/Graphics.java | 6 ++++-- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/forge-gui-android/pom.xml b/forge-gui-android/pom.xml index 6d5bf55aa7c..f581ef4fd60 100644 --- a/forge-gui-android/pom.xml +++ b/forge-gui-android/pom.xml @@ -102,7 +102,7 @@ com.badlogicgames.gdx gdx-backend-android - 1.9.11 + 1.9.10 diff --git a/forge-gui-ios/pom.xml b/forge-gui-ios/pom.xml index 8b1a741a5ee..a34a6d9e8fd 100644 --- a/forge-gui-ios/pom.xml +++ b/forge-gui-ios/pom.xml @@ -73,7 +73,7 @@ com.badlogicgames.gdx gdx-backend-robovm - 1.9.11 + 1.9.10 diff --git a/forge-gui-mobile-dev/pom.xml b/forge-gui-mobile-dev/pom.xml index 4cd801f7408..14aacfe4a26 100644 --- a/forge-gui-mobile-dev/pom.xml +++ b/forge-gui-mobile-dev/pom.xml @@ -60,18 +60,18 @@ com.badlogicgames.gdx gdx-backend-lwjgl - 1.9.11 + 1.9.10 com.badlogicgames.gdx gdx-platform - 1.9.11 + 1.9.10 natives-desktop com.badlogicgames.gdx gdx-freetype-platform - 1.9.11 + 1.9.10 natives-desktop diff --git a/forge-gui-mobile/pom.xml b/forge-gui-mobile/pom.xml index b3eb00fd614..339886fa293 100644 --- a/forge-gui-mobile/pom.xml +++ b/forge-gui-mobile/pom.xml @@ -63,12 +63,12 @@ com.badlogicgames.gdx gdx - 1.9.11 + 1.9.10 com.badlogicgames.gdx gdx-freetype - 1.9.11 + 1.9.10 diff --git a/forge-gui-mobile/src/forge/Graphics.java b/forge-gui-mobile/src/forge/Graphics.java index fb2cf05335e..d503653abaf 100644 --- a/forge-gui-mobile/src/forge/Graphics.java +++ b/forge-gui-mobile/src/forge/Graphics.java @@ -680,11 +680,12 @@ public class Graphics { batch.draw(image, adjustX(x), adjustY(y, h), w, h); } else { batch.end(); - shaderOutline.bind(); + shaderOutline.begin(); shaderOutline.setUniformf("u_viewportInverse", new Vector2(1f / w, 1f / h)); shaderOutline.setUniformf("u_offset", 3f); shaderOutline.setUniformf("u_step", Math.min(1f, w / 70f)); shaderOutline.setUniformf("u_color", new Vector3(glowColor.r, glowColor.g, glowColor.b)); + shaderOutline.end(); batch.setShader(shaderOutline); batch.begin(); //glow @@ -703,11 +704,12 @@ public class Graphics { batch.draw(image, adjustX(x), adjustY(yBox, h), w, h); } else { batch.end(); - shaderOutline.bind(); + shaderOutline.begin(); shaderOutline.setUniformf("u_viewportInverse", new Vector2(1f / w, 1f / h)); shaderOutline.setUniformf("u_offset", 3f); shaderOutline.setUniformf("u_step", Math.min(1f, w / 70f)); shaderOutline.setUniformf("u_color", new Vector3(glowColor.r, glowColor.g, glowColor.b)); + shaderOutline.end(); batch.setShader(shaderOutline); batch.begin(); //glow From 63b5eac6b94ca3c8ebe06b6d83805dceefd7f105 Mon Sep 17 00:00:00 2001 From: Sol Date: Wed, 23 Dec 2020 19:21:29 +0000 Subject: [PATCH 81/97] Update bell_borca_spectral_sergeant.txt --- forge-gui/res/cardsfolder/b/bell_borca_spectral_sergeant.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge-gui/res/cardsfolder/b/bell_borca_spectral_sergeant.txt b/forge-gui/res/cardsfolder/b/bell_borca_spectral_sergeant.txt index 0ef1f7333e4..40d534cdec2 100644 --- a/forge-gui/res/cardsfolder/b/bell_borca_spectral_sergeant.txt +++ b/forge-gui/res/cardsfolder/b/bell_borca_spectral_sergeant.txt @@ -1,5 +1,5 @@ Name:Bell Borca, Spectral Sergeant -ManaCost:2 B R +ManaCost:2 R W Types:Legendary Creature Spirit Soldier PT:*/5 Text:Note the converted mana cost of each card as it's put into exile. From e0688d74584d8bd1ab4fa0d7eef2592b96090bb9 Mon Sep 17 00:00:00 2001 From: Bug Hunter Date: Fri, 25 Dec 2020 09:46:01 +0000 Subject: [PATCH 82/97] Fix hand hiding after controlled turns --- forge-game/src/main/java/forge/game/Game.java | 2 +- forge-game/src/main/java/forge/game/player/Player.java | 4 +++- .../src/main/java/forge/screens/match/CMatchUI.java | 6 ++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/forge-game/src/main/java/forge/game/Game.java b/forge-game/src/main/java/forge/game/Game.java index 2886947a065..991a219048d 100644 --- a/forge-game/src/main/java/forge/game/Game.java +++ b/forge-game/src/main/java/forge/game/Game.java @@ -439,10 +439,10 @@ public class Game { } public synchronized void setGameOver(GameEndReason reason) { - age = GameStage.GameOver; for (Player p : allPlayers) { p.clearController(); } + age = GameStage.GameOver; for (Player p : getPlayers()) { p.onGameOver(); diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index 3cf09db7d1f..c199f58a88e 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -2574,6 +2574,8 @@ public class Player extends GameEntity implements Comparable { final PlayerController oldController = getController(); controlledBy.remove(timestamp); + getView().updateMindSlaveMaster(this); + if (event) { game.fireEvent(new GameEventPlayerControl(this, oldLobbyPlayer, oldController, getLobbyPlayer(), getController())); } @@ -2581,9 +2583,9 @@ public class Player extends GameEntity implements Comparable { public void clearController() { controlledBy.clear(); + game.fireEvent(new GameEventPlayerControl(this, null, null, getLobbyPlayer(), getController())); } - public Map.Entry getControlledWhileSearching() { if (controlledWhileSearching.isEmpty()) { return null; diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java index a505d104ac5..1c191c8b1d1 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java @@ -793,9 +793,11 @@ public final class CMatchUI initHandViews(); SLayoutIO.loadLayout(null); view.populate(); - for (final VHand h : getHandViews()) { - h.getLayoutControl().updateHand(); + final PlayerZoneUpdates zones = new PlayerZoneUpdates(); + for (final PlayerView p : sortedPlayers) { + zones.add(new PlayerZoneUpdate(p, ZoneType.Hand)); } + updateZones(zones); } @Override From d8f010d54a788ec14ef51ccf0c5d5412543adaa1 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Fri, 25 Dec 2020 23:23:06 +0100 Subject: [PATCH 83/97] DestroyAI: better logic for Pongify also Update for X --- .../main/java/forge/ai/SpecialAiLogic.java | 109 +++++--- .../main/java/forge/ai/SpellAbilityAi.java | 6 +- .../main/java/forge/ai/ability/DestroyAi.java | 242 +++++++++--------- .../java/forge/game/cost/CostDiscard.java | 10 + .../forge/game/spellability/SpellAbility.java | 12 +- .../res/cardsfolder/s/scorched_earth.txt | 2 +- 6 files changed, 214 insertions(+), 167 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/SpecialAiLogic.java b/forge-ai/src/main/java/forge/ai/SpecialAiLogic.java index 6a378ea6d0f..c757133f256 100644 --- a/forge-ai/src/main/java/forge/ai/SpecialAiLogic.java +++ b/forge-ai/src/main/java/forge/ai/SpecialAiLogic.java @@ -1,6 +1,10 @@ package forge.ai; +import java.util.List; + import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; + import forge.ai.ability.TokenAi; import forge.game.Game; import forge.game.ability.AbilityUtils; @@ -12,8 +16,6 @@ import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; -import forge.game.zone.ZoneType; import forge.util.Aggregates; /* @@ -31,60 +33,83 @@ public class SpecialAiLogic { Card source = sa.getHostCard(); Game game = source.getGame(); PhaseHandler ph = game.getPhaseHandler(); - TargetRestrictions tgt = sa.getTargetRestrictions(); + boolean isDestroy = ApiType.Destroy.equals(sa.getApi()); + SpellAbility tokenSA = sa.findSubAbilityByType(ApiType.Token); + if (tokenSA == null) { + // Used wrong AI logic? + return false; + } - CardCollection listOpp = CardLists.getValidCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), ai, source, sa); - listOpp = CardLists.getTargetableCards(listOpp, sa); + List targetable = CardUtil.getValidCardsToTarget(sa.getTargetRestrictions(), sa); - Card choice = ComputerUtilCard.getMostExpensivePermanentAI(listOpp); + CardCollection listOpp = CardLists.filterControlledBy(targetable, ai.getOpponents()); + if (isDestroy) { + listOpp = CardLists.getNotKeyword(listOpp, Keyword.INDESTRUCTIBLE); + // TODO add handling for cards like targeting dies + } - final Card token = choice != null ? TokenAi.spawnToken(choice.getController(), sa.getSubAbility()) : null; - if (token == null || !token.isCreature() || token.getNetToughness() < 1) { - return true; // becomes Terminate - } else if (choice != null && choice.isPlaneswalker()) { - if (choice.getCurrentLoyalty() * 35 > ComputerUtilCard.evaluateCreature(token)) { - sa.resetTargets(); - sa.getTargets().add(choice); - return true; - } else { - return false; + Card choice = null; + if (!listOpp.isEmpty()) { + choice = ComputerUtilCard.getMostExpensivePermanentAI(listOpp); + // can choice even be null? + + if (choice != null) { + final Card token = TokenAi.spawnToken(choice.getController(), tokenSA); + if (!token.isCreature() || token.getNetToughness() < 1) { + sa.resetTargets(); + sa.getTargets().add(choice); + return true; + } + if (choice.isPlaneswalker()) { + if (choice.getCurrentLoyalty() * 35 > ComputerUtilCard.evaluateCreature(token)) { + sa.resetTargets(); + sa.getTargets().add(choice); + return true; + } else { + return false; + } + } + if ((!choice.isCreature() || choice.isTapped()) && ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS) && ph.isPlayerTurn(ai) // prevent surprise combatant + || ComputerUtilCard.evaluateCreature(choice) < 1.5 * ComputerUtilCard.evaluateCreature(token)) { + choice = null; + } } - } else { - boolean hasOppTarget = true; - if (choice != null - && ((!choice.isCreature() || choice.isTapped()) && ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS) && ph.getPlayerTurn() == ai) // prevent surprise combatant - || ComputerUtilCard.evaluateCreature(choice) < 1.5 * ComputerUtilCard.evaluateCreature(token)) { + } - hasOppTarget = false; + // See if we have anything we can upgrade + if (choice == null) { + CardCollection listOwn = CardLists.filterControlledBy(targetable, ai); + final Card token = TokenAi.spawnToken(ai, tokenSA); + + Card bestOwnCardToUpgrade = null; + if (isDestroy) { + // just choose any Indestructible + // TODO maybe filter something that doesn't like to be targeted, or does something benefit by targeting + bestOwnCardToUpgrade = Iterables.getFirst(CardLists.getKeyword(listOwn, Keyword.INDESTRUCTIBLE), null); } - - // See if we have anything we can upgrade - if (!hasOppTarget) { - CardCollection listOwn = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), ai, source, sa); - listOwn = CardLists.getTargetableCards(listOwn, sa); - - Card bestOwnCardToUpgrade = ComputerUtilCard.getWorstCreatureAI(CardLists.filter(listOwn, new Predicate() { + if (bestOwnCardToUpgrade == null) { + bestOwnCardToUpgrade = ComputerUtilCard.getWorstCreatureAI(CardLists.filter(listOwn, new Predicate() { @Override public boolean apply(Card card) { return card.isCreature() && (ComputerUtilCard.isUselessCreature(ai, card) || ComputerUtilCard.evaluateCreature(token) > 2 * ComputerUtilCard.evaluateCreature(card)); } })); - if (bestOwnCardToUpgrade != null) { - if (ComputerUtilCard.isUselessCreature(ai, bestOwnCardToUpgrade) || (ph.getPhase().isAfter(PhaseType.COMBAT_END) || ph.getPlayerTurn() != ai)) { - sa.resetTargets(); - sa.getTargets().add(bestOwnCardToUpgrade); - return true; - } - } - } else { - sa.resetTargets(); - sa.getTargets().add(choice); - return true; } - - return hasOppTarget; + if (bestOwnCardToUpgrade != null) { + if (ComputerUtilCard.isUselessCreature(ai, bestOwnCardToUpgrade) || (ph.getPhase().isAfter(PhaseType.COMBAT_END) || !ph.isPlayerTurn(ai))) { + choice = bestOwnCardToUpgrade; + } + } } + + if (choice != null) { + sa.resetTargets(); + sa.getTargets().add(choice); + return true; + } + + return false; } // A logic for cards that say "Sacrifice a creature: CARDNAME gets +X/+X until EOT" diff --git a/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java b/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java index 6b78b69b223..fa33c11087a 100644 --- a/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java +++ b/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java @@ -78,10 +78,14 @@ public abstract class SpellAbilityAi { } } + if (!checkApiLogic(ai, sa)) { + return false; + } + // needs to be after API logic because needs to check possible X Cost? if (cost != null && !willPayCosts(ai, sa, cost, source)) { return false; } - return checkApiLogic(ai, sa); + return true; } protected boolean checkConditions(final Player ai, final SpellAbility sa, SpellAbilityCondition con) { diff --git a/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java b/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java index 33108116b0c..1c8c72f6e32 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DestroyAi.java @@ -13,7 +13,6 @@ import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.game.zone.ZoneType; public class DestroyAi extends SpellAbilityAi { @@ -23,89 +22,19 @@ public class DestroyAi extends SpellAbilityAi { } @Override - protected boolean canPlayAI(final Player ai, SpellAbility sa) { - // AI needs to be expanded, since this function can be pretty complex - // based on what the expected targets could be - final Cost abCost = sa.getPayCosts(); - final TargetRestrictions abTgt = sa.getTargetRestrictions(); + protected boolean checkAiLogic(final Player ai, final SpellAbility sa, final String aiLogic) { final Card source = sa.getHostCard(); - final boolean noRegen = sa.hasParam("NoRegen"); - final String logic = sa.getParam("AILogic"); - boolean hasXCost = false; - - CardCollection list; - - if (abCost != null) { - if (!ComputerUtilCost.checkSacrificeCost(ai, abCost, source, sa)) { - return false; - } - - if (!ComputerUtilCost.checkLifeCost(ai, abCost, source, 4, sa)) { - return false; - } - - if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source)) { - return false; - } - - hasXCost = sa.costHasManaX(); - } - - if ("AtOpponentsCombatOrAfter".equals(sa.getParam("AILogic"))) { - PhaseHandler ph = ai.getGame().getPhaseHandler(); - if (ph.getPlayerTurn() == ai || ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) { - return false; - } - } else if ("AtEOT".equals(sa.getParam("AILogic"))) { - PhaseHandler ph = ai.getGame().getPhaseHandler(); - if (!ph.is(PhaseType.END_OF_TURN)) { - return false; - } - } else if ("AtEOTIfNotAttacking".equals(sa.getParam("AILogic"))) { - PhaseHandler ph = ai.getGame().getPhaseHandler(); - if (!ph.is(PhaseType.END_OF_TURN) || !ai.getCreaturesAttackedThisTurn().isEmpty()) { - return false; - } - } - - if (ComputerUtil.preventRunAwayActivations(sa)) { - return false; - } - - // Ability that's intended to destroy own useless token to trigger Grave Pacts - // should be fired at end of turn or when under attack after blocking to make opponent sac something - boolean havepact = false; - - // TODO replace it with look for a dies -> sacrifice trigger check - havepact |= ai.isCardInPlay("Grave Pact"); - havepact |= ai.isCardInPlay("Butcher of Malakir"); - havepact |= ai.isCardInPlay("Dictate of Erebos"); - if ("Pactivator".equals(logic) && havepact) { - if ((!ai.getGame().getPhaseHandler().isPlayerTurn(ai)) - && ((ai.getGame().getPhaseHandler().is(PhaseType.END_OF_TURN)) || (ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS))) - && (ai.getOpponents().getCreaturesInPlay().size() > 0)) { - ai.getController().chooseTargetsFor(sa); - return true; - } - } - - // Targeting - if (abTgt != null) { + if (sa.usesTargeting()) { sa.resetTargets(); - if (sa.hasParam("TargetingPlayer")) { - Player targetingPlayer = AbilityUtils.getDefinedPlayers(source, sa.getParam("TargetingPlayer"), sa).get(0); - sa.setTargetingPlayer(targetingPlayer); - return targetingPlayer.getController().chooseTargetsFor(sa); - } - if ("MadSarkhanDragon".equals(logic)) { + if ("MadSarkhanDragon".equals(aiLogic)) { return SpecialCardAi.SarkhanTheMad.considerMakeDragon(ai, sa); - } else if (logic != null && logic.startsWith("MinLoyalty.")) { - int minLoyalty = Integer.parseInt(logic.substring(logic.indexOf(".") + 1)); + } else if (aiLogic.startsWith("MinLoyalty.")) { + int minLoyalty = Integer.parseInt(aiLogic.substring(aiLogic.indexOf(".") + 1)); if (source.getCounters(CounterEnumType.LOYALTY) < minLoyalty) { return false; } - } else if ("Polymorph".equals(logic)) { - list = CardLists.getTargetableCards(ai.getCardsIn(ZoneType.Battlefield), sa); + } else if ("Polymorph".equals(aiLogic)) { + CardCollection list = CardLists.getTargetableCards(ai.getCardsIn(ZoneType.Battlefield), sa); if (list.isEmpty()) { return false; } @@ -124,7 +53,108 @@ public class DestroyAi extends SpellAbilityAi { } sa.getTargets().add(worst); return true; + } else if ("Pongify".equals(aiLogic)) { + return SpecialAiLogic.doPongifyLogic(ai, sa); } + } + return super.checkAiLogic(ai, sa, aiLogic); + } + + protected boolean checkPhaseRestrictions(final Player ai, final SpellAbility sa, final PhaseHandler ph, + final String logic) { + if ("AtOpponentsCombatOrAfter".equals(logic)) { + if (ph.isPlayerTurn(ai) || ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) { + return false; + } + } else if ("AtEOT".equals(logic)) { + if (!ph.is(PhaseType.END_OF_TURN)) { + return false; + } + } else if ("AtEOTIfNotAttacking".equals(logic)) { + if (!ph.is(PhaseType.END_OF_TURN) || !ai.getCreaturesAttackedThisTurn().isEmpty()) { + return false; + } + } else if ("Pactivator".equals(logic)) { + // Ability that's intended to destroy own useless token to trigger Grave Pacts + // should be fired at end of turn or when under attack after blocking to make opponent sac something + boolean havepact = false; + + // TODO replace it with look for a dies -> sacrifice trigger check + havepact |= ai.isCardInPlay("Grave Pact"); + havepact |= ai.isCardInPlay("Butcher of Malakir"); + havepact |= ai.isCardInPlay("Dictate of Erebos"); + if (havepact) { + if ((!ph.isPlayerTurn(ai)) + && ((ph.is(PhaseType.END_OF_TURN)) || (ph.is(PhaseType.COMBAT_DECLARE_BLOCKERS))) + && (ai.getOpponents().getCreaturesInPlay().size() > 0)) { + CardCollection list = CardLists.getTargetableCards(ai.getCardsIn(ZoneType.Battlefield), sa); + Card worst = ComputerUtilCard.getWorstAI(list); + if (worst != null) { + sa.getTargets().add(worst); + return true; + } + return false; + } + } + } + + return true; + } + + @Override + protected boolean checkApiLogic(final Player ai, final SpellAbility sa) { + final Card source = sa.getHostCard(); + final boolean noRegen = sa.hasParam("NoRegen"); + final String logic = sa.getParam("AILogic"); + + CardCollection list; + + + + if (ComputerUtil.preventRunAwayActivations(sa)) { + return false; + } + + + // Targeting + if (sa.usesTargeting()) { + // Assume there where already enough targets chosen by AI Logic Above + if (!sa.canAddMoreTarget() && sa.isTargetNumberValid()) { + return true; + } + + // reset targets before AI Logic part + sa.resetTargets(); + int maxTargets; + + if (sa.costHasManaX()) { + // TODO: currently the AI will maximize mana spent on X, trying to maximize damage. This may need improvement. + maxTargets = ComputerUtilCost.getMaxXValue(sa, ai); + // need to set XPaid to get the right number for + sa.setXManaCostPaid(maxTargets); + // need to check for maxTargets + maxTargets = Math.min(maxTargets, sa.getMaxTargets()); + } else { + maxTargets = sa.getMaxTargets(); + } + if (sa.hasParam("AIMaxTgtsCount")) { + // Cards that have confusing costs for the AI (e.g. Eliminate the Competition) can have forced max target constraints specified + // TODO: is there a better way to predict things like "sac X" costs without needing a special AI variable? + maxTargets = Math.min(CardFactoryUtil.xCount(sa.getHostCard(), "Count$" + sa.getParam("AIMaxTgtsCount")), maxTargets); + } + + if (maxTargets == 0) { + // can't afford X or otherwise target anything + return false; + } + + if (sa.hasParam("TargetingPlayer")) { + Player targetingPlayer = AbilityUtils.getDefinedPlayers(source, sa.getParam("TargetingPlayer"), sa).get(0); + sa.setTargetingPlayer(targetingPlayer); + return targetingPlayer.getController().chooseTargetsFor(sa); + } + + // AI doesn't destroy own cards if it isn't defined in AI logic list = CardLists.getTargetableCards(ai.getOpponents().getCardsIn(ZoneType.Battlefield), sa); if ("FatalPush".equals(logic)) { final int cmcMax = ai.hasRevolt() ? 4 : 2; @@ -184,33 +214,12 @@ public class DestroyAi extends SpellAbilityAi { return false; } - int maxTargets = abTgt.getMaxTargets(sa.getHostCard(), sa); - - if (hasXCost) { - // TODO: currently the AI will maximize mana spent on X, trying to maximize damage. This may need improvement. - maxTargets = Math.min(ComputerUtilMana.determineMaxAffordableX(ai, sa), abTgt.getMaxTargets(sa.getHostCard(), sa)); - // X can't be more than the lands we have in our hand for "discard X lands"! - if ("ScorchedEarth".equals(logic)) { - int lands = CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.Presets.LANDS).size(); - maxTargets = Math.min(maxTargets, lands); - } - } - if (sa.hasParam("AIMaxTgtsCount")) { - // Cards that have confusing costs for the AI (e.g. Eliminate the Competition) can have forced max target constraints specified - // TODO: is there a better way to predict things like "sac X" costs without needing a special AI variable? - maxTargets = Math.min(CardFactoryUtil.xCount(sa.getHostCard(), "Count$" + sa.getParam("AIMaxTgtsCount")), maxTargets); - } - - if (maxTargets == 0) { - // can't afford X or otherwise target anything - return false; - } // target loop + // TODO use can add more Targets while (sa.getTargets().size() < maxTargets) { if (list.isEmpty()) { - if ((sa.getTargets().size() < abTgt.getMinTargets(sa.getHostCard(), sa)) - || (sa.getTargets().size() == 0)) { + if (!sa.isMinTargetChosen() || sa.isZeroTargets()) { sa.resetTargets(); return false; } else { @@ -222,10 +231,6 @@ public class DestroyAi extends SpellAbilityAi { Card choice = null; // If the targets are only of one type, take the best if (CardLists.getNotType(list, "Creature").isEmpty()) { - if ("Pongify".equals(logic)) { - return SpecialAiLogic.doPongifyLogic(ai, sa); - } - choice = ComputerUtilCard.getBestCreatureAI(list); if ("OppDestroyYours".equals(logic)) { Card aiBest = ComputerUtilCard.getBestCreatureAI(ai.getCreaturesInPlay()); @@ -246,15 +251,14 @@ public class DestroyAi extends SpellAbilityAi { choice = ComputerUtilCard.getMostExpensivePermanentAI(list, sa, true); } //option to hold removal instead only applies for single targeted removal - if (!sa.isTrigger() && abTgt.getMaxTargets(sa.getHostCard(), sa) == 1) { + if (!sa.isTrigger() && sa.getMaxTargets() == 1) { if (choice == null || !ComputerUtilCard.useRemovalNow(sa, choice, 0, ZoneType.Graveyard)) { return false; } } if (choice == null) { // can't find anything left - if ((sa.getTargets().size() < abTgt.getMinTargets(sa.getHostCard(), sa)) - || (sa.getTargets().size() == 0)) { + if (!sa.isMinTargetChosen() || sa.isZeroTargets()) { sa.resetTargets(); return false; } else { @@ -298,22 +302,19 @@ public class DestroyAi extends SpellAbilityAi { @Override protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) { - final TargetRestrictions tgt = sa.getTargetRestrictions(); - final Card source = sa.getHostCard(); final boolean noRegen = sa.hasParam("NoRegen"); - if (tgt != null) { + if (sa.usesTargeting()) { sa.resetTargets(); CardCollection list = CardLists.getTargetableCards(ai.getGame().getCardsIn(ZoneType.Battlefield), sa); - list = CardLists.getValidCards(list, tgt.getValidTgts(), source.getController(), source, sa); + + if (list.isEmpty() || list.size() < sa.getMinTargets()) { + return false; + } // Try to avoid targeting creatures that are dead on board list = ComputerUtil.filterCreaturesThatWillDieThisTurn(ai, list, sa); - if (list.isEmpty() || list.size() < tgt.getMinTargets(sa.getHostCard(), sa)) { - return false; - } - CardCollection preferred = CardLists.getNotKeyword(list, Keyword.INDESTRUCTIBLE); preferred = CardLists.filterControlledBy(preferred, ai.getOpponents()); if (CardLists.getNotType(preferred, "Creature").isEmpty()) { @@ -344,10 +345,9 @@ public class DestroyAi extends SpellAbilityAi { return false; } - while (sa.getTargets().size() < tgt.getMaxTargets(sa.getHostCard(), sa)) { + while (sa.canAddMoreTarget()) { if (preferred.isEmpty()) { - if (sa.getTargets().size() == 0 - || sa.getTargets().size() < tgt.getMinTargets(sa.getHostCard(), sa)) { + if (!sa.isMinTargetChosen()) { if (!mandatory) { sa.resetTargets(); return false; @@ -371,7 +371,7 @@ public class DestroyAi extends SpellAbilityAi { } } - while (sa.getTargets().size() < tgt.getMinTargets(sa.getHostCard(), sa)) { + while (sa.canAddMoreTarget()) { if (list.isEmpty()) { break; } else { @@ -392,7 +392,7 @@ public class DestroyAi extends SpellAbilityAi { } } - return sa.getTargets().size() >= tgt.getMinTargets(sa.getHostCard(), sa); + return sa.isTargetNumberValid(); } else { return mandatory; } diff --git a/forge-game/src/main/java/forge/game/cost/CostDiscard.java b/forge-game/src/main/java/forge/game/cost/CostDiscard.java index 3edd069cfde..a51f5409a38 100644 --- a/forge-game/src/main/java/forge/game/cost/CostDiscard.java +++ b/forge-game/src/main/java/forge/game/cost/CostDiscard.java @@ -65,6 +65,16 @@ public class CostDiscard extends CostPartWithList { public int paymentOrder() { return 10; } + @Override + public Integer getMaxAmountX(SpellAbility ability, Player payer) { + final Card source = ability.getHostCard(); + String type = this.getType(); + CardCollectionView handList = payer.canDiscardBy(ability) ? payer.getCardsIn(ZoneType.Hand) : CardCollection.EMPTY; + + handList = CardLists.getValidCards(handList, type.split(";"), payer, source, ability); + return handList.size(); + } + /* * (non-Javadoc) * diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java index 0f9d07fcf00..d9e04293f5e 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -1391,7 +1391,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit return false; } - return getTargets().size() < getTargetRestrictions().getMaxTargets(hostCard, this); + return getTargets().size() < getMaxTargets(); } public boolean isZeroTargets() { @@ -1405,6 +1405,14 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit return getTargetRestrictions().isMaxTargetsChosen(hostCard, this); } + public int getMinTargets() { + return getTargetRestrictions().getMinTargets(getHostCard(), this); + } + + public int getMaxTargets() { + return getTargetRestrictions().getMaxTargets(getHostCard(), this); + } + public boolean isTargetNumberValid() { if (!this.usesTargeting()) { return getTargets().isEmpty(); @@ -1413,7 +1421,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit if (!isMinTargetChosen()) { return false; } - int maxTargets = getTargetRestrictions().getMaxTargets(hostCard, this); + int maxTargets = getMaxTargets(); if (maxTargets == 0 && getPayCosts().hasSpecificCostType(CostRemoveCounter.class) && hasSVar(getParam("TargetMax")) diff --git a/forge-gui/res/cardsfolder/s/scorched_earth.txt b/forge-gui/res/cardsfolder/s/scorched_earth.txt index 291ca501892..60bb6747e7f 100644 --- a/forge-gui/res/cardsfolder/s/scorched_earth.txt +++ b/forge-gui/res/cardsfolder/s/scorched_earth.txt @@ -1,7 +1,7 @@ Name:Scorched Earth ManaCost:X R Types:Sorcery -A:SP$ Destroy | Cost$ X R Discard | CostDesc$ As an additional cost to cast this spell, discard X land cards. | TargetMin$ X | TargetMax$ X | ValidTgts$ Land | TgtPrompt$ Select X target lands | References$ X | SpellDescription$ Destroy X target lands. | AILogic$ ScorchedEarth +A:SP$ Destroy | Cost$ X R Discard | CostDesc$ As an additional cost to cast this spell, discard X land cards. | TargetMin$ X | TargetMax$ X | ValidTgts$ Land | TgtPrompt$ Select X target lands | References$ X | SpellDescription$ Destroy X target lands. SVar:X:Count$xPaid AI:RemoveDeck:Random SVar:PlayBeforeLandDrop:true From df72493dc45a9927287bdaeed1e2e7630e51664b Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Sat, 26 Dec 2020 16:25:32 +0800 Subject: [PATCH 84/97] Removed Unused Import --- forge-game/src/main/java/forge/game/cost/PaymentDecision.java | 1 - 1 file changed, 1 deletion(-) diff --git a/forge-game/src/main/java/forge/game/cost/PaymentDecision.java b/forge-game/src/main/java/forge/game/cost/PaymentDecision.java index e10ff87eb11..17c35140a44 100644 --- a/forge-game/src/main/java/forge/game/cost/PaymentDecision.java +++ b/forge-game/src/main/java/forge/game/cost/PaymentDecision.java @@ -3,7 +3,6 @@ package forge.game.cost; import forge.game.GameEntityCounterTable; import forge.game.card.Card; import forge.game.card.CardCollection; -import forge.game.card.CounterType; import forge.game.mana.Mana; import forge.game.player.Player; import forge.game.spellability.SpellAbility; From 97b8c2463e6603c4b8b6248bd411aa7eb7e75f36 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Sat, 26 Dec 2020 22:21:53 +0100 Subject: [PATCH 85/97] Fix Exception by closing Dialog --- forge-gui/src/main/java/forge/download/AutoUpdater.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge-gui/src/main/java/forge/download/AutoUpdater.java b/forge-gui/src/main/java/forge/download/AutoUpdater.java index 8e731be5c55..99ce308bd8c 100644 --- a/forge-gui/src/main/java/forge/download/AutoUpdater.java +++ b/forge-gui/src/main/java/forge/download/AutoUpdater.java @@ -79,7 +79,7 @@ public class AutoUpdater { String message = localizer.getMessage("lblYouHaventSetUpdateChannel"); List options = ImmutableList.of("Cancel", "release", "snapshot"); int option = SOptionPane.showOptionDialog(message, localizer.getMessage("lblManualCheck"), null, options, 0); - if (option == 0) { + if (option < 1) { return false; } else { updateChannel = options.get(option); From 48411df77a3aec20fd1ff8fb9e221004df55c1f2 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Tue, 22 Dec 2020 11:15:52 -0500 Subject: [PATCH 86/97] absorb_identity.txt --- .../res/cardsfolder/upcoming/absorb_identity.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/absorb_identity.txt diff --git a/forge-gui/res/cardsfolder/upcoming/absorb_identity.txt b/forge-gui/res/cardsfolder/upcoming/absorb_identity.txt new file mode 100644 index 00000000000..617f3b81f6a --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/absorb_identity.txt @@ -0,0 +1,12 @@ +Name:Absorb Identity +ManaCost:1 U +Types:Instant +A:SP$ ChangeZone | Cost$ 1 U | ValidTgts$ Creature | TgtPrompt$ Select target creature | Origin$ Battlefield | Destination$ Hand | RememberChanged$ True | SubAbility$ DBChoice | SpellDescription$ Return target creature to its owner's hand. You may have Shapeshifters you control become copies of that creature until end of turn. +SVar:DBChoice:DB$ GenericChoice | Choices$ CloneArmy,DBNoop | Defined$ You | SubAbility$ DBCleanup | StackDesription$ You may have Shapeshifters you control become copies of that creature until end of turn. +SVar:CloneArmy:DB$ RepeatEach | UseImprinted$ True | RepeatCards$ Shapeshifter.YouCtrl | RepeatSubAbility$ DBCopy | SpellDescription$ Shapeshifters you control become copies of that creature until end of turn. +SVar:DBCopy:DB$ Clone | Defined$ Remembered | CloneTarget$ Imprinted | Duration$ UntilEndOfTurn +SVar:DBNoop:DB$ Cleanup | SpellDescription$ Do nothing. +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True +DeckHints:Type$Shapeshifter +AI:RemoveDeck:All +Oracle:Return target creature to its owner's hand. You may have Shapeshifters you control become copies of that creature until end of turn. From d939c22c7f7fa2ec7d29c98d77bf421d10de2b77 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Tue, 22 Dec 2020 11:44:44 -0500 Subject: [PATCH 87/97] elderfang_ritualist.txt --- .../res/cardsfolder/upcoming/elderfang_ritualist.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/elderfang_ritualist.txt diff --git a/forge-gui/res/cardsfolder/upcoming/elderfang_ritualist.txt b/forge-gui/res/cardsfolder/upcoming/elderfang_ritualist.txt new file mode 100644 index 00000000000..752f485603d --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/elderfang_ritualist.txt @@ -0,0 +1,10 @@ +Name:Elderfang Ritualist +ManaCost:2 B +Types:Creature Elf Cleric +PT:3/1 +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigChangeZone | TriggerDescription$ When CARDNAME dies, return another target Elf card from your graveyard to your hand. +SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | ValidTgts$ Elf.Other+YouOwn | TgtPrompt$ Select another target Elf card from your graveyard +SVar:SacMe:2 +DeckNeeds:Type$Elf +DeckHas:Ability$Graveyard +Oracle:When Elderfang Ritualist dies, return another target Elf card from your graveyard to your hand. From 43c5a6b95890e0980b3842c94aaf49b4780c65f2 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Tue, 22 Dec 2020 11:45:02 -0500 Subject: [PATCH 88/97] gladewalker_ritualist.txt --- .../res/cardsfolder/upcoming/gladewalker_ritualist.txt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/gladewalker_ritualist.txt diff --git a/forge-gui/res/cardsfolder/upcoming/gladewalker_ritualist.txt b/forge-gui/res/cardsfolder/upcoming/gladewalker_ritualist.txt new file mode 100644 index 00000000000..138512afaa1 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/gladewalker_ritualist.txt @@ -0,0 +1,9 @@ +Name:Gladewalker Ritualist +ManaCost:2 G +Types:Creature Shapeshifter +PT:3/3 +K:Changeling +T:Mode$ ChangesZone | ValidCard$ Creature.YouCtrl+Other+namedGladewalker Ritualist | Origin$ Any | Destination$ Battlefield | Execute$ TrigDraw | TriggerZones$ Battlefield | TriggerDescription$ Whenever another creature named Gladewalker Ritualist enters the battlefield under your control, draw a card. +SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1 +DeckHints:Name$Gladewalker Ritualist +Oracle:Changeling (This card is every creature type.)\nWhenever another creature named Gladewalker Ritualist enters the battlefield under your control, draw a card. From 9547495120a78a68d52bc0274916a03d363ddc39 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Tue, 22 Dec 2020 12:25:31 -0500 Subject: [PATCH 89/97] bearded_axe.txt --- forge-gui/res/cardsfolder/upcoming/bearded_axe.txt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/bearded_axe.txt diff --git a/forge-gui/res/cardsfolder/upcoming/bearded_axe.txt b/forge-gui/res/cardsfolder/upcoming/bearded_axe.txt new file mode 100644 index 00000000000..3f53e700690 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/bearded_axe.txt @@ -0,0 +1,8 @@ +Name:Bearded Axe +ManaCost:2 R +Types:Artifact Equipment +S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ X | AddToughness$ X | References$ X | Description$ Equipped creature gets +1/+1 for each Dwarf, Equipment, and/or Vehicle you control. +K:Equip:2 +SVar:X:Count$Valid Dwarf.YouCtrl,Equipment.YouCtrl,Vehicle.YouCtrl +DeckHints:Type$Dwarf|Equipment|Vehicle +Oracle:Equipped creature gets +1/+1 for each Dwarf, Equipment, and/or Vehicle you control.\nEquip {2} From eb1f0e7a2b1e2be2bb6e32658f62c12b253eb55a Mon Sep 17 00:00:00 2001 From: Northmoc Date: Tue, 22 Dec 2020 12:25:49 -0500 Subject: [PATCH 90/97] thornmantle_striker.txt --- .../res/cardsfolder/upcoming/thornmantle_striker.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/thornmantle_striker.txt diff --git a/forge-gui/res/cardsfolder/upcoming/thornmantle_striker.txt b/forge-gui/res/cardsfolder/upcoming/thornmantle_striker.txt new file mode 100644 index 00000000000..e2838446169 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/thornmantle_striker.txt @@ -0,0 +1,11 @@ +Name:Thornmantle Striker +ManaCost:4 B +Types:Creature Elf Rogue +PT:4/3 +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigCharm | TriggerDescription$ When CARDNAME enters the battlefield, ABILITY +SVar:TrigCharm:DB$ Charm | Choices$ DBRemoveCounter,DBPump +SVar:DBRemoveCounter:DB$ RemoveCounter | ValidTgts$ Permanent | TgtPrompt$ Select target permanent | CounterType$ Any | CounterNum$ X | References$ X | SpellDescription$ Remove X counters from target permanent, where X is the number of Elves you control. +SVar:DBPump:DB$ Pump | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | IsCurse$ True | NumAtt$ -X | NumDef$ -X | References$ X | SpellDescription$ Target creature an opponent controls gets -X/-X until end of turn, where X is the number of Elves you control. +SVar:X:Count$Valid Elf.YouCtrl +DeckNeeds:Type$Elf +Oracle:When Thornmantle Striker enters the battlefield, choose one —\n• Remove X counters from target permanent, where X is the number of Elves you control.\n• Target creature an opponent controls gets -X/-X until end of turn, where X is the number of Elves you control. From d617b5ed7fe07984bc077059a1d1c274a9c541cf Mon Sep 17 00:00:00 2001 From: Northmoc Date: Tue, 22 Dec 2020 12:55:12 -0500 Subject: [PATCH 91/97] elven_ambush.txt --- forge-gui/res/cardsfolder/upcoming/elven_ambush.txt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/elven_ambush.txt diff --git a/forge-gui/res/cardsfolder/upcoming/elven_ambush.txt b/forge-gui/res/cardsfolder/upcoming/elven_ambush.txt new file mode 100644 index 00000000000..8c2c5a8b62a --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/elven_ambush.txt @@ -0,0 +1,9 @@ +Name:Elven Ambush +ManaCost:3 G +Types:Instant +A:SP$ Token | Cost$ 3 G | TokenAmount$ X | References$ X | TokenScript$ g_1_1_elf_warrior | TokenOwner$ You | SpellDescription$ Create a 1/1 green Elf Warrior creature token for each Elf you control. +SVar:X:Count$Valid Elf.YouCtrl +DeckHas:Ability$Token +DeckNeeds:Type$Elf +AI:RemoveDeck:Random +Oracle:Create a 1/1 green Elf Warrior creature token for each Elf you control. From 02a4f2b0a9f75cd01e893db5ebf3c7bc80d58026 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Tue, 22 Dec 2020 13:15:52 -0500 Subject: [PATCH 92/97] gilded_assault_cart.txt --- .../res/cardsfolder/upcoming/gilded_assault_cart.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/gilded_assault_cart.txt diff --git a/forge-gui/res/cardsfolder/upcoming/gilded_assault_cart.txt b/forge-gui/res/cardsfolder/upcoming/gilded_assault_cart.txt new file mode 100644 index 00000000000..295bebf28e7 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/gilded_assault_cart.txt @@ -0,0 +1,10 @@ +Name:Gilded Assault Cart +ManaCost:1 R R +Types:Artifact Vehicle +PT:5/1 +K:Trample +K:Crew:2 +A:AB$ ChangeZone | Cost$ Sac<2/Treasure> | CostDesc$ Sacrifice two Treasures: | Origin$ Graveyard | Destination$ Hand | ActivationZone$ Graveyard | SpellDescription$ Return CARDNAME from your graveyard to your hand. +DeckHas:Ability$Sacrifice +AI:RemoveDeck:Random +Oracle:Trample\nCrew 2 (Tap any number of creatures you control with total power 2 or more: This Vehicle becomes an artifact creature until end of turn.)\nSacrifice two Treasures: Return Gilded Assault Cart from your graveyard to your hand. From d043294efd13b5b0289af59b2fe2b96344c38966 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Tue, 22 Dec 2020 15:54:04 -0500 Subject: [PATCH 93/97] fire_giants_fury.txt --- .../res/cardsfolder/upcoming/fire_giants_fury.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/fire_giants_fury.txt diff --git a/forge-gui/res/cardsfolder/upcoming/fire_giants_fury.txt b/forge-gui/res/cardsfolder/upcoming/fire_giants_fury.txt new file mode 100644 index 00000000000..ae2301eb86c --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/fire_giants_fury.txt @@ -0,0 +1,14 @@ +Name:Fire Giant's Fury +ManaCost:1 R +Types:Sorcery +A:SP$ Pump | Cost$ 1 R | ValidTgts$ Giant.YouCtrl | TgtPrompt$ Select target Giant you control | NumAtt$ +2 | NumDef$ +2 | KW$ Trample | SubAbility$ DBCombatDamageEffect | StackDescription$ {c:Targeted} gets +2/+2 and gains trample until end of turn. Whenever it deals combat damage to a player this turn, exile that many cards from the top of your library. Until the end of your next turn, you may play those cards. | SpellDescription$ Target Giant you control gets +2/+2 and gains trample until end of turn. Whenever it deals combat damage to a player this turn, exile that many cards from the top of your library. Until the end of your next turn, you may play those cards. +SVar:DBCombatDamageEffect:DB$ Effect | ImprintCards$ Targeted | Triggers$ DealCombatDamagePlayer | SVars$ TrigExile,DBEffect,X,STPlay,DBCleanup | SubAbility$ DBCleanup +SVar:DealCombatDamagePlayer:Mode$ DamageDone | ValidSource$ Card.IsImprinted | ValidTarget$ Player | Execute$ TrigExile | CombatDamage$ True | TriggerDescription$ Whenever this Giant deals combat damage to a player this turn, exile that many cards from the top of your library. Until the end of your next turn, you may play those cards. +SVar:TrigExile:DB$ Dig | Defined$ You | DigNum$ X | References$ X | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | SubAbility$ DBEffect +SVar:DBEffect:DB$ Effect | StaticAbilities$ STPlay | ForgetOnMoved$ Exile | RememberObjects$ RememberedCard | Duration$ UntilTheEndOfYourNextTurn | SubAbility$ DBCleanup +SVar:STPlay:Mode$ Continuous | EffectZone$ Command | Affected$ Card.IsRemembered | MayPlay$ True | AffectedZone$ Exile | Description$ Until the end of your next turn, you may play those cards. +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True +SVar:X:TriggerCount$DamageAmount +DeckNeeds:Type$Giant +AI:RemoveDeck:Random +Oracle:Target Giant you control gets +2/+2 and gains trample until end of turn. Whenever it deals combat damage to a player this turn, exile that many cards from the top of your library. Until the end of your next turn, you may play those cards. From 53bd5f90673265d05956f6c522e961544cd6986b Mon Sep 17 00:00:00 2001 From: Northmoc Date: Wed, 15 Jul 2020 12:21:42 -0400 Subject: [PATCH 94/97] making Panglacial Wurm work --- .../main/java/forge/game/ability/effects/ChangeZoneEffect.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java index e938a9f9973..2a7956c90ea 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java @@ -947,10 +947,12 @@ public class ChangeZoneEffect extends SpellAbilityEffect { if (!decider.getController().confirmAction(tgtSA, null, Localizer.getInstance().getMessage("lblDoYouWantPlayCard", CardTranslation.getTranslatedName(tgtCard.getName())))) { continue; } + tgtSA.setSVar("IsCastFromPlayEffect", "True"); // if played, that card cannot be found if (decider.getController().playSaFromPlayEffect(tgtSA)) { fetchList.remove(tgtCard); } + //some kind of reset here? } } final Map runParams = AbilityKey.newMap(); From fd106d789f045c93b2930aa9c78799edf2bb29ce Mon Sep 17 00:00:00 2001 From: Northmoc Date: Tue, 29 Dec 2020 17:29:12 -0500 Subject: [PATCH 95/97] hazezon_tamar.txt and rukh_egg.txt fix --- forge-gui/res/cardsfolder/h/hazezon_tamar.txt | 9 +++++---- forge-gui/res/cardsfolder/r/rukh_egg.txt | 8 ++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/forge-gui/res/cardsfolder/h/hazezon_tamar.txt b/forge-gui/res/cardsfolder/h/hazezon_tamar.txt index f031278ce43..ba10de6003e 100644 --- a/forge-gui/res/cardsfolder/h/hazezon_tamar.txt +++ b/forge-gui/res/cardsfolder/h/hazezon_tamar.txt @@ -3,10 +3,11 @@ ManaCost:4 R G W Types:Legendary Creature Human Warrior PT:2/4 T:Mode$ ChangesZone | ValidCard$ Creature.Self | Origin$ Any | Destination$ Battlefield | Execute$ DelTrig | TriggerDescription$ When CARDNAME enters the battlefield, create X 1/1 Sand Warrior creature tokens that are red, green, and white at the beginning of your next upkeep, where X is the number of lands you control at that time. -SVar:DelTrig:DB$ DelayedTrigger | Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | Execute$ TrigTokens | TriggerController$ TriggeredCardController | RememberObjects$ TriggeredCardController | TriggerDescription$ Create a 1/1 Sand Warrior creature token that are red, green, and white for each land you control. -SVar:TrigTokens:DB$ Token | TokenAmount$ X | TokenScript$ rgw_1_1_sand_warrior | TokenOwner$ DelayTriggerRemembered | LegacyImage$ rgw 1 1 sand warrior leg | References$ X -T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Battlefield | Destination$ Any | Execute$ TrigExile | TriggerDescription$ When Hazezon leaves the battlefield, exile all Sand Warriors. +SVar:DelTrig:DB$ DelayedTrigger | Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | Execute$ TrigTokens | TriggerDescription$ Create X 1/1 Sand Warrior creature tokens that are red, green, and white, where X is the number of lands you control. +SVar:TrigTokens:DB$ Token | TokenAmount$ X | TokenScript$ rgw_1_1_sand_warrior | TokenOwner$ You | References$ X +T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Battlefield | Destination$ Any | Execute$ TrigExile | TriggerDescription$ When CARDNAME leaves the battlefield, exile all Sand Warriors. +#NICKNAME upgrade SVar:TrigExile:DB$ ChangeZoneAll | Origin$ Battlefield | Destination$ Exile | ChangeType$ Sand.Warrior SVar:X:Count$Valid Land.YouCtrl -SVar:Picture:http://www.wizards.com/global/images/magic/general/hazezon_tamar.jpg +DeckHas:Ability$Token Oracle:When Hazezon Tamar enters the battlefield, create X 1/1 Sand Warrior creature tokens that are red, green, and white at the beginning of your next upkeep, where X is the number of lands you control at that time.\nWhen Hazezon leaves the battlefield, exile all Sand Warriors. diff --git a/forge-gui/res/cardsfolder/r/rukh_egg.txt b/forge-gui/res/cardsfolder/r/rukh_egg.txt index fc091aea87e..5baebd36c41 100644 --- a/forge-gui/res/cardsfolder/r/rukh_egg.txt +++ b/forge-gui/res/cardsfolder/r/rukh_egg.txt @@ -2,10 +2,10 @@ Name:Rukh Egg ManaCost:3 R Types:Creature Bird Egg PT:0/3 -T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ DelTrigLeaves | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, create a 4/4 red Bird creature token with flying at the beginning of the next end step. -SVar:DelTrigLeaves:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ TrigToken | TriggerController$ TriggeredCardController | TriggerDescription$ Create a 4/4 red Bird creature token with flying at the beginning of the next end step. -SVar:TrigToken:DB$ Token | TokenOwner$ You | TokenScript$ r_4_4_bird_flying | LegacyImage$ r 4 4 bird flying arn | TokenAmount$ 1 +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ DelTrigLeaves | TriggerDescription$ When CARDNAME dies, create a 4/4 red Bird creature token with flying at the beginning of the next end step. +SVar:DelTrigLeaves:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ TrigToken | TriggerDescription$ Create a 4/4 red Bird creature token with flying at the beginning of the next end step. +SVar:TrigToken:DB$ Token | TokenOwner$ You | TokenScript$ r_4_4_bird_flying | TokenAmount$ 1 SVar:SacMe:4 DeckHas:Ability$Token -SVar:Picture:http://www.wizards.com/global/images/magic/general/rukh_egg.jpg +DeckHints:Ability$Sacrifice Oracle:When Rukh Egg dies, create a 4/4 red Bird creature token with flying at the beginning of the next end step. From ab2a16a707b5637ec6f10d1b43c413495e023500 Mon Sep 17 00:00:00 2001 From: Northmoc Date: Tue, 29 Dec 2020 19:07:06 -0500 Subject: [PATCH 96/97] ludevic_necro_alchemist.txt --- forge-gui/res/cardsfolder/l/ludevic_necro_alchemist.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/forge-gui/res/cardsfolder/l/ludevic_necro_alchemist.txt b/forge-gui/res/cardsfolder/l/ludevic_necro_alchemist.txt index 0c9ef6c8076..2da49610f6d 100644 --- a/forge-gui/res/cardsfolder/l/ludevic_necro_alchemist.txt +++ b/forge-gui/res/cardsfolder/l/ludevic_necro_alchemist.txt @@ -3,7 +3,6 @@ ManaCost:1 U R Types:Legendary Creature Human Wizard PT:1/4 T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ Player | Execute$ DrawDamageOther | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of each player's end step, that player may draw a card if a player other than you lost life this turn. -SVar:DrawDamageOther:DB$ Draw | Defined$ TriggeredPlayer | NumCards$ 1 | ConditionPlayerContains$ Player.Other+wasDealtDamageThisTurn | ConditionPlayerDefined$ Player | OptionalDecider$ True +SVar:DrawDamageOther:DB$ Draw | Defined$ TriggeredPlayer | NumCards$ 1 | ConditionPlayerDefined$ Player.Other | ConditionPlayerContains$ Player.wasDealtDamageThisTurn | OptionalDecider$ True K:Partner -SVar:Picture:http://www.wizards.com/global/images/magic/general/ludevic_necro-alchemist.jpg -Oracle:At the beginning of each player's end step, that player may draw a card if a player other than you lost life this turn.\nPartner (You can have two commanders if both have partner.) \ No newline at end of file +Oracle:At the beginning of each player's end step, that player may draw a card if a player other than you lost life this turn.\nPartner (You can have two commanders if both have partner.) From f700b9d43b973074b5fa9fb0c6ff13d030e05d0c Mon Sep 17 00:00:00 2001 From: Tim Mocny Date: Wed, 30 Dec 2020 02:35:25 +0000 Subject: [PATCH 97/97] Butcher Orgg!!! --- .../main/java/forge/game/card/CardView.java | 3 + .../main/java/forge/game/combat/Combat.java | 56 +++++++++++++++---- .../forge/trackable/TrackableProperty.java | 1 + .../screens/match/VAssignCombatDamage.java | 19 +++++-- .../match/views/VAssignCombatDamage.java | 13 ++++- forge-gui/res/cardsfolder/b/butcher_orgg.txt | 7 +++ forge-gui/res/languages/de-DE.properties | 1 + forge-gui/res/languages/en-US.properties | 1 + forge-gui/res/languages/es-ES.properties | 1 + forge-gui/res/languages/it-IT.properties | 1 + forge-gui/res/languages/zh-CN.properties | 1 + .../forge/player/PlayerControllerHuman.java | 4 +- 12 files changed, 87 insertions(+), 21 deletions(-) create mode 100644 forge-gui/res/cardsfolder/b/butcher_orgg.txt diff --git a/forge-game/src/main/java/forge/game/card/CardView.java b/forge-game/src/main/java/forge/game/card/CardView.java index c848700e2a6..2a3fb86f417 100644 --- a/forge-game/src/main/java/forge/game/card/CardView.java +++ b/forge-game/src/main/java/forge/game/card/CardView.java @@ -1133,6 +1133,7 @@ public class CardView extends GameEntityView { public boolean hasDeathtouch() { return get(TrackableProperty.HasDeathtouch); } public boolean hasDevoid() { return get(TrackableProperty.HasDevoid); } public boolean hasDefender() { return get(TrackableProperty.HasDefender); } + public boolean hasDivideDamage() { return get(TrackableProperty.HasDivideDamage); } public boolean hasDoubleStrike() { return get(TrackableProperty.HasDoubleStrike); } public boolean hasFirstStrike() { return get(TrackableProperty.HasFirstStrike); } public boolean hasFlying() { return get(TrackableProperty.HasFlying); } @@ -1173,6 +1174,8 @@ public class CardView extends GameEntityView { set(TrackableProperty.HasDeathtouch, c.hasKeyword(Keyword.DEATHTOUCH, state)); set(TrackableProperty.HasDevoid, c.hasKeyword(Keyword.DEVOID, state)); set(TrackableProperty.HasDefender, c.hasKeyword(Keyword.DEFENDER, state)); + set(TrackableProperty.HasDivideDamage, c.hasKeyword("You may assign CARDNAME's combat damage divided as " + + "you choose among defending player and/or any number of creatures they control.")); set(TrackableProperty.HasDoubleStrike, c.hasKeyword(Keyword.DOUBLE_STRIKE, state)); set(TrackableProperty.HasFirstStrike, c.hasKeyword(Keyword.FIRST_STRIKE, state)); set(TrackableProperty.HasFlying, c.hasKeyword(Keyword.FLYING, state)); diff --git a/forge-game/src/main/java/forge/game/combat/Combat.java b/forge-game/src/main/java/forge/game/combat/Combat.java index 4c85ccd5cac..992fce3b3bf 100644 --- a/forge-game/src/main/java/forge/game/combat/Combat.java +++ b/forge-game/src/main/java/forge/game/combat/Combat.java @@ -20,21 +20,18 @@ package forge.game.combat; import com.google.common.base.Function; import com.google.common.collect.*; import forge.game.Game; -import forge.game.GameEntity; -import forge.game.GameEntityCounterTable; -import forge.game.GameLogEntryType; -import forge.game.GameObjectMap; +import forge.game.*; import forge.game.ability.AbilityKey; -import forge.game.card.Card; -import forge.game.card.CardCollection; -import forge.game.card.CardCollectionView; -import forge.game.card.CardDamageMap; +import forge.game.card.*; import forge.game.keyword.Keyword; import forge.game.player.Player; import forge.game.spellability.SpellAbilityStackInstance; import forge.game.trigger.TriggerType; +import forge.game.zone.ZoneType; +import forge.util.CardTranslation; import forge.util.collect.FCollection; import forge.util.collect.FCollectionView; +import forge.util.Localizer; import org.apache.commons.lang3.tuple.Pair; import java.util.*; @@ -64,6 +61,7 @@ public class Combat { private Map blockersOrderedForDamageAssignment = Maps.newHashMap(); private Map lkiCache = Maps.newHashMap(); private CardDamageMap dealtDamageTo = new CardDamageMap(); + private boolean dividedToPlayer = false; // List holds creatures who have dealt 1st strike damage to disallow them deal damage on regular basis (unless they have double-strike KW) private CardCollection combatantsThatDealtFirstStrikeDamage = new CardCollection(); @@ -373,7 +371,7 @@ public class Combat { blocker.updateBlockingForView(); } - // remove blocked from specific attacker + // remove blocker from specific attacker public final void removeBlockAssignment(final Card attacker, final Card blocker) { AttackingBand band = getBandOfAttackerNotNull(attacker); Collection cc = blockedBands.get(band); @@ -400,6 +398,15 @@ public class Combat { return result; } + public final CardCollection getDefendersCreatures() { + CardCollection result = new CardCollection(); + for (Card attacker : getAttackers()) { + CardCollection cc = getDefenderPlayerByAttacker(attacker).getCreaturesInPlay(); + result.addAll(cc); + } + return result; + } + public final CardCollection getBlockers(final AttackingBand band) { Collection blockers = blockedBands.get(band); return blockers == null ? new CardCollection() : new CardCollection(blockers); @@ -716,8 +723,26 @@ public class Combat { continue; } + boolean divideCombatDamageAsChoose = (getDefendersCreatures().size() > 0 && + attacker.hasKeyword("You may assign CARDNAME's combat damage divided as you choose among " + + "defending player and/or any number of creatures they control.") + && attacker.getController().getController().confirmAction(null, null, + Localizer.getInstance().getMessage("lblAssignCombatDamageAsChoose", + CardTranslation.getTranslatedName(attacker.getName())))); boolean trampler = attacker.hasKeyword(Keyword.TRAMPLE); orderedBlockers = blockersOrderedForDamageAssignment.get(attacker); + if (divideCombatDamageAsChoose) { + if (orderedBlockers == null || orderedBlockers.isEmpty()) { + orderedBlockers = getDefendersCreatures(); + } + else { + for (Card c : getDefendersCreatures()) { + if (!orderedBlockers.contains(c)) { + orderedBlockers.add(c); + } + } + } + } assignedDamage = true; // If the Attacker is unblocked, or it's a trampler and has 0 blockers, deal damage to defender if (orderedBlockers == null || orderedBlockers.isEmpty()) { @@ -730,6 +755,10 @@ public class Combat { Player assigningPlayer = getAttackingPlayer(); // Defensive Formation is very similar to Banding with Blockers // It allows the defending player to assign damage instead of the attacking player + if (defender instanceof Card && divideCombatDamageAsChoose) { + defender = getDefenderPlayerByAttacker(attacker); + dividedToPlayer = true; + } if (defender instanceof Player && defender.hasKeyword("You assign combat damage of each creature attacking you.")) { assigningPlayer = (Player)defender; } @@ -737,7 +766,8 @@ public class Combat { assigningPlayer = orderedBlockers.get(0).getController(); } - Map map = assigningPlayer.getController().assignCombatDamage(attacker, orderedBlockers, damageDealt, defender, getAttackingPlayer() != assigningPlayer); + Map map = assigningPlayer.getController().assignCombatDamage(attacker, orderedBlockers, + damageDealt, defender, divideCombatDamageAsChoose || getAttackingPlayer() != assigningPlayer); for (Entry dt : map.entrySet()) { if (dt.getKey() == null) { if (dt.getValue() > 0) @@ -767,7 +797,7 @@ public class Combat { private final void addDefendingDamage(final int n, final Card source) { final GameEntity ge = getDefenderByAttacker(source); - if (ge instanceof Card) { + if (ge instanceof Card && !dividedToPlayer) { final Card planeswalker = (Card) ge; planeswalker.addAssignedDamage(n, source); return; @@ -805,6 +835,9 @@ public class Combat { // This function handles both Regular and First Strike combat assignment for (final Entry entry : defendingDamageMap.entrySet()) { GameEntity defender = getDefenderByAttacker(entry.getKey()); + if (dividedToPlayer) { + defender = getDefenderPlayerByAttacker(entry.getKey()); + } if (defender instanceof Player) { // player defender.addCombatDamage(entry.getValue(), entry.getKey(), dealtDamageTo, preventMap, counterTable); } @@ -819,6 +852,7 @@ public class Combat { combatants.addAll(getAttackers()); combatants.addAll(getAllBlockers()); combatants.addAll(getDefendingPlaneswalkers()); + combatants.addAll(getDefendersCreatures()); for (final Card c : combatants) { // if no assigned damage to resolve, move to next diff --git a/forge-game/src/main/java/forge/trackable/TrackableProperty.java b/forge-game/src/main/java/forge/trackable/TrackableProperty.java index 2bc1d95c063..9b46a396fd5 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableProperty.java +++ b/forge-game/src/main/java/forge/trackable/TrackableProperty.java @@ -100,6 +100,7 @@ public enum TrackableProperty { HasDeathtouch(TrackableTypes.BooleanType), HasDevoid(TrackableTypes.BooleanType), HasDefender(TrackableTypes.BooleanType), + HasDivideDamage(TrackableTypes.BooleanType), HasDoubleStrike(TrackableTypes.BooleanType), HasFirstStrike(TrackableTypes.BooleanType), HasFlying(TrackableTypes.BooleanType), diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/VAssignCombatDamage.java b/forge-gui-desktop/src/main/java/forge/screens/match/VAssignCombatDamage.java index 673e4950c89..4cebdcc3491 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/VAssignCombatDamage.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/VAssignCombatDamage.java @@ -74,6 +74,7 @@ public class VAssignCombatDamage { private final int totalDamageToAssign; private boolean attackerHasDeathtouch = false; + private boolean attackerHasDivideDamage = false; private boolean attackerHasTrample = false; private boolean attackerHasInfect = false; private boolean overrideCombatantOrder = false; @@ -152,6 +153,7 @@ public class VAssignCombatDamage { attackerHasDeathtouch = attacker.getCurrentState().hasDeathtouch(); attackerHasInfect = attacker.getCurrentState().hasInfect(); attackerHasTrample = defender != null && attacker.getCurrentState().hasTrample(); + attackerHasDivideDamage = attacker.getCurrentState().hasDivideDamage(); overrideCombatantOrder = overrideOrder; // Top-level UI stuff @@ -173,7 +175,7 @@ public class VAssignCombatDamage { // Defenders area final JPanel pnlDefenders = new JPanel(); pnlDefenders.setOpaque(false); - int cols = attackerHasTrample ? blockers.size() + 1 : blockers.size(); + int cols = ((attackerHasTrample) || (attackerHasDivideDamage && overrideCombatantOrder)) ? blockers.size() + 1 : blockers.size(); final String wrap = "wrap " + cols; pnlDefenders.setLayout(new MigLayout("insets 0, gap 0, ax center, " + wrap)); @@ -187,7 +189,7 @@ public class VAssignCombatDamage { addPanelForDefender(pnlDefenders, c); } - if (attackerHasTrample) { + if ((attackerHasTrample) || (attackerHasDivideDamage && overrideCombatantOrder)) { final DamageTarget dt = new DamageTarget(null, new FLabel.Builder().text("0").fontSize(18).fontAlign(SwingConstants.CENTER).build()); damage.put(null, dt); defenders.add(dt); @@ -275,10 +277,12 @@ public class VAssignCombatDamage { source = null; // If trying to assign to the defender, follow the normal assignment rules - // No need to check for "active" creature assignee when overiding combatant order - if ((source == null || source == defender || !overrideCombatantOrder) && isAdding && - !VAssignCombatDamage.this.canAssignTo(source)) { - return; + // No need to check for "active" creature assignee when overriding combatant order + if (!attackerHasDivideDamage) { // Creatures with this can assign to defender + if ((source == null || source == defender || !overrideCombatantOrder) && isAdding && + !VAssignCombatDamage.this.canAssignTo(source)) { + return; + } } // If lethal damage has already been assigned just act like it's 0. @@ -316,6 +320,9 @@ public class VAssignCombatDamage { } private void checkDamageQueue() { + if (overrideCombatantOrder && attackerHasDivideDamage) { + return; + } // Clear out any Damage that shouldn't be assigned to other combatants boolean hasAliveEnemy = false; for(DamageTarget dt : defenders) { diff --git a/forge-gui-mobile/src/forge/screens/match/views/VAssignCombatDamage.java b/forge-gui-mobile/src/forge/screens/match/views/VAssignCombatDamage.java index 6b709930750..f85881795bd 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VAssignCombatDamage.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VAssignCombatDamage.java @@ -61,6 +61,7 @@ public class VAssignCombatDamage extends FDialog { private final int totalDamageToAssign; private boolean attackerHasDeathtouch = false; + private boolean attackerHasDivideDamage = false; private boolean attackerHasTrample = false; private boolean attackerHasInfect = false; private boolean overrideCombatantOrder = false; @@ -102,6 +103,7 @@ public class VAssignCombatDamage extends FDialog { totalDamageToAssign = damage0; defender = defender0; attackerHasDeathtouch = attacker.getCurrentState().hasDeathtouch(); + attackerHasDivideDamage = attacker.getCurrentState().hasDivideDamage(); attackerHasInfect = attacker.getCurrentState().hasInfect(); attackerHasTrample = defender != null && attacker.getCurrentState().hasTrample(); overrideCombatantOrder = overrideOrder; @@ -166,7 +168,7 @@ public class VAssignCombatDamage extends FDialog { addDamageTarget(c); } - if (attackerHasTrample) { + if (attackerHasTrample || (attackerHasDivideDamage && overrideCombatantOrder)) { //add damage target for target of attack that trample damage will go through to addDamageTarget(null); } @@ -298,8 +300,10 @@ public class VAssignCombatDamage extends FDialog { // If trying to assign to the defender, follow the normal assignment rules // No need to check for "active" creature assignee when overiding combatant order - if ((source == null || source == defender || !overrideCombatantOrder) && isAdding && !canAssignTo(source)) { - return; + if (!attackerHasDivideDamage) { // Creatures with this can assign to defender + if ((source == null || source == defender || !overrideCombatantOrder) && isAdding && !canAssignTo(source)) { + return; + } } // If lethal damage has already been assigned just act like it's 0. @@ -330,6 +334,9 @@ public class VAssignCombatDamage extends FDialog { } private void checkDamageQueue() { + if (overrideCombatantOrder && attackerHasDivideDamage) { + return; + } // Clear out any Damage that shouldn't be assigned to other combatants boolean hasAliveEnemy = false; for (DamageTarget dt : defenders) { diff --git a/forge-gui/res/cardsfolder/b/butcher_orgg.txt b/forge-gui/res/cardsfolder/b/butcher_orgg.txt new file mode 100644 index 00000000000..120e3ed6c58 --- /dev/null +++ b/forge-gui/res/cardsfolder/b/butcher_orgg.txt @@ -0,0 +1,7 @@ +Name:Butcher Orgg +ManaCost:4 R R R +Types:Creature Orgg +PT:6/6 +K:You may assign CARDNAME's combat damage divided as you choose among defending player and/or any number of creatures they control. +AI:RemoveDeck:All +Oracle:You may assign Butcher Orgg’s combat damage divided as you choose among defending player and/or any number of creatures they control. diff --git a/forge-gui/res/languages/de-DE.properties b/forge-gui/res/languages/de-DE.properties index 45a2f6bfd0d..b3227352818 100644 --- a/forge-gui/res/languages/de-DE.properties +++ b/forge-gui/res/languages/de-DE.properties @@ -1170,6 +1170,7 @@ lblDraw=Ziehen lblTooFewCardsMainDeck=Zu wenig Karten in deinem Deck (mindestens {0}). Bitte passe dein Deck an. lblTooManyCardsSideboard=Zu viele Karten in deinem Deck (maximal {0}). Bitte passe dein Deck an. lblAssignCombatDamageWerentBlocked=Möchtest du den Kampfschaden deklarieren, als wäre nicht geblockt worden? +lblAssignCombatDamageAsChoose=Do you want to divide {0}''s combat damage as you choose? lblChosenCards=Wähle Karten lblAttacker=Angreifer lblTriggeredby=Ausgelöst durch diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index c4cca0dd335..d58cacccd0c 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -1170,6 +1170,7 @@ lblDraw=Draw lblTooFewCardsMainDeck=Too few cards in your main deck (minimum {0}), please make modifications to your deck again. lblTooManyCardsSideboard=Too many cards in your sideboard (maximum {0}), please make modifications to your deck again. lblAssignCombatDamageWerentBlocked=Do you want to assign its combat damage as though it weren''t blocked? +lblAssignCombatDamageAsChoose=Do you want to divide {0}''s combat damage as you choose? lblChosenCards=Chosen Cards lblAttacker=Attacker lblTriggeredby=Triggered by diff --git a/forge-gui/res/languages/es-ES.properties b/forge-gui/res/languages/es-ES.properties index adf0243c33e..69636b23831 100644 --- a/forge-gui/res/languages/es-ES.properties +++ b/forge-gui/res/languages/es-ES.properties @@ -1170,6 +1170,7 @@ lblDraw=Ceder lblTooFewCardsMainDeck=Muy pocas cartas en tu mazo principal (mínimo {0}), por favor realiza modificaciones a tu mazo de nuevo. lblTooManyCardsSideboard=Demasiadas cartas en tu banquillo (máximo {0}), por favor realiza modificaciones a tu mazo de nuevo. lblAssignCombatDamageWerentBlocked=¿Quieres asignar su daño de combate como si no estuviera bloqueado? +lblAssignCombatDamageAsChoose=¿Quieres dividir el daño de combate del {0} como elijas? lblChosenCards=Cartas elegidas lblAttacker=Atacante lblTriggeredby=Activado por diff --git a/forge-gui/res/languages/it-IT.properties b/forge-gui/res/languages/it-IT.properties index f4476649095..f76b760c73a 100644 --- a/forge-gui/res/languages/it-IT.properties +++ b/forge-gui/res/languages/it-IT.properties @@ -1170,6 +1170,7 @@ lblDraw=Disegnare lblTooFewCardsMainDeck=Troppe carte nel tuo mazzo principale (minimo %s), per favore apporta nuovamente modifiche al tuo mazzo. lblTooManyCardsSideboard=Troppe carte nel tuo sideboard (massimo %s), modifica nuovamente il tuo mazzo. lblAssignCombatDamageWerentBlocked=Vuoi assegnare il suo danno da combattimento come se non fosse bloccato? +lblAssignCombatDamageAsChoose=Vuoi suddividere come preferisci il danno da combattimento dell''{0}? lblChosenCards=Carte scelte lblAttacker=aggressore lblTriggeredby=Innescato da diff --git a/forge-gui/res/languages/zh-CN.properties b/forge-gui/res/languages/zh-CN.properties index 0441ac02e3c..b05f7adcdeb 100644 --- a/forge-gui/res/languages/zh-CN.properties +++ b/forge-gui/res/languages/zh-CN.properties @@ -1170,6 +1170,7 @@ lblDraw=后手 lblTooFewCardsMainDeck=主牌中卡牌数过少(最少为{0}),请重新修改套牌。 lblTooManyCardsSideboard=备牌中卡牌数过多(最多为{0}),请重新修改套牌。 lblAssignCombatDamageWerentBlocked=是否要像没有被阻挡一样分配战斗伤害? +lblAssignCombatDamageAsChoose=你想要按你所选的分配方式对{0}造成战斗伤害吗? lblChosenCards=选择牌 lblAttacker=进攻者 lblTriggeredby=触发者 diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index 6ee56cc6811..e2d31e40556 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -286,7 +286,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont if (defender != null && assignDamageAsIfNotBlocked(attacker)) { map.put(null, damageDealt); } else { - if ((attacker.hasKeyword(Keyword.TRAMPLE) && defender != null) || (blockers.size() > 1)) { + if ((attacker.hasKeyword(Keyword.TRAMPLE) && defender != null) || (blockers.size() > 1) + || (attacker.hasKeyword("You may assign CARDNAME's combat damage divided as you choose among defending" + + " player and/or any number of creatures they control.")) && overrideOrder && blockers.size() >0) { GameEntityViewMap gameCacheBlockers = GameEntityView.getMap(blockers); final CardView vAttacker = CardView.get(attacker); final GameEntityView vDefender = GameEntityView.get(defender);