diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GrabbagImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GrabbagImageSource.java index 7db9fa2970e..ab56977114d 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GrabbagImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GrabbagImageSource.java @@ -204,7 +204,7 @@ public enum GrabbagImageSource implements CardImageSource { singleLinks.put("SWS/Hazard Trooper", "ZOutamG.jpeg"); singleLinks.put("SWS/Head Hunting", "7OT1bGZ.jpeg"); singleLinks.put("SWS/Heavy Trooper", "HhZWs2N.jpeg"); - singleLinks.put("SWS/Hot Pursuit", "ih1GT5Z.jpeg"); + singleLinks.put("SWS/Hot Pursuit (Star Wars)", "ih1GT5Z.jpeg"); singleLinks.put("SWS/Hungry Dragonsnake", "23v7RTm.jpeg"); singleLinks.put("SWS/Hunt to Extinction", "3eJyfzZ.jpeg"); singleLinks.put("SWS/Hutt Crime Lord", "NAzK7Hp.jpeg"); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java index 1c64712ad5a..8ca97816777 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java @@ -439,7 +439,7 @@ public class ScryfallImageSupportCards { add("ELD"); // Throne of Eldraine //add("PTG"); // Ponies: The Galloping add("CMB1"); // Mystery Booster Playtest Cards 2019 - //add("MB1"); // Mystery Booster + add("MB1"); // Mystery Booster add("GN2"); // Game Night 2019 add("HA1"); // Historic Anthology 1 //add("HHO"); // Happy Holidays @@ -534,7 +534,7 @@ public class ScryfallImageSupportCards { add("ONE"); // Phyrexia: All Will Be One add("ONC"); // Phyrexia: All Will Be One Commander add("PL23"); // Year of the Rabbit 2023 - add("DA1"); // Unknown Event + add("UNK"); // Unknown Event add("SIS"); // Shadows of the Past add("SIR"); // Shadows over Innistrad Remastered add("SLP"); // Secret Lair Showdown @@ -683,8 +683,16 @@ public class ScryfallImageSupportCards { // CALC - custom alchemy version of cards. put("CALC/C-Pillar of the Paruns", "https://api.scryfall.com/cards/dis/176/"); + // MB1 + put("MB1/Goblin Trenches", "https://api.scryfall.com/cards/plst/EMA-203/"); + put("MB1/Prophetic Bolt", "https://api.scryfall.com/cards/plst/C15-231/"); + // LTR - 0 number for tokens only - put("LTR/The One Ring/001", "https://api.scryfall.com/cards/ltr/0/"); + // Scryfall has a bug, for some reason this link doesn't work with ?format=image even though it works with ?format=json + // and ?format=text. Base url fails because language is qya and not en and alternate url fails because of this bug + // TODO: This should be reverted when Scryfall fixes the bug + // put("LTR/The One Ring/001", "https://api.scryfall.com/cards/ltr/0/"); + put("LTR/The One Ring/001", "https://api.scryfall.com/cards/ltr/0/qya?format=image"); // REX - double faced lands (xmage uses two diff lands for it) put("REX/Command Tower/26b", "https://api.scryfall.com/cards/rex/26/en?format=image&face=back"); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java index d8dc2cd18c2..9441b6aa677 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java @@ -39,7 +39,8 @@ public class ScryfallImageSupportTokens { putAll(TokenRepository.instance.prepareScryfallDownloadList()); // RIX - put("RIX/City's Blessing", "https://api.scryfall.com/cards/trix/6/en?format=image"); // TODO: missing from tokens data + // TODO: this should be readded when condition tokens are implemented + // put("RIX/City's Blessing", "https://api.scryfall.com/cards/trix/6/en?format=image"); put("RIX/Elemental/1", "https://api.scryfall.com/cards/trix/1/en?format=image"); put("RIX/Elemental/2", "https://api.scryfall.com/cards/trix/2/en?format=image"); put("RIX/Golem", "https://api.scryfall.com/cards/trix/4/en?format=image"); @@ -117,22 +118,6 @@ public class ScryfallImageSupportTokens { put("AKH/Warrior", "https://api.scryfall.com/cards/takh/17/en?format=image"); put("AKH/Wurm", "https://api.scryfall.com/cards/takh/24/en?format=image"); put("AKH/Zombie", "https://api.scryfall.com/cards/takh/20/en?format=image"); - // AKH - embalm ability (token from card) - put("AKH/Angel of Sanctions", "https://api.scryfall.com/cards/takh/1/en?format=image"); - put("AKH/Anointer Priest", "https://api.scryfall.com/cards/takh/2/en?format=image"); - put("AKH/Aven Initiate", "https://api.scryfall.com/cards/takh/3/en?format=image"); - put("AKH/Aven Wind Guide", "https://api.scryfall.com/cards/takh/4/en?format=image"); - put("AKH/Glyph Keeper", "https://api.scryfall.com/cards/takh/5/en?format=image"); - put("AKH/Heart-Piercer Manticore", "https://api.scryfall.com/cards/takh/6/en?format=image"); - put("AKH/Honored Hydra", "https://api.scryfall.com/cards/takh/7/en?format=image"); - put("AKH/Labyrinth Guardian", "https://api.scryfall.com/cards/takh/8/en?format=image"); - put("AKH/Oketra's Attendant", "https://api.scryfall.com/cards/takh/9/en?format=image"); - put("AKH/Sacred Cat", "https://api.scryfall.com/cards/takh/10/en?format=image"); - put("AKH/Tah-Crop Skirmisher", "https://api.scryfall.com/cards/takh/11/en?format=image"); - put("AKH/Temmet, Vizier of Naktamun", "https://api.scryfall.com/cards/takh/12/en?format=image"); - put("AKH/Trueheart Duelist", "https://api.scryfall.com/cards/takh/13/en?format=image"); - put("AKH/Unwavering Initiate", "https://api.scryfall.com/cards/takh/14/en?format=image"); - put("AKH/Vizier of Many Faces", "https://api.scryfall.com/cards/takh/15/en?format=image"); // AER put("AER/Etherium Cell", "https://api.scryfall.com/cards/taer/3/en?format=image"); @@ -501,7 +486,7 @@ public class ScryfallImageSupportTokens { put("ZNC/Elemental/1", "https://api.scryfall.com/cards/tznc/10/en?format=image"); // 5/5 put("ZNC/Elemental/2", "https://api.scryfall.com/cards/tznc/8/en?format=image"); // 2/2 put("ZNC/Faerie Rogue", "https://api.scryfall.com/cards/tznc/3/en?format=image"); - put("ZNC/Germ", "https://api.scryfall.com/cards/tznc/4/en?format=image"); // must be in chest or antology + put("ZNC/Phyrexian Germ", "https://api.scryfall.com/cards/tznc/4/en?format=image"); // must be in chest or antology put("ZNC/Goblin Rogue", "https://api.scryfall.com/cards/tznc/5/en?format=image"); put("ZNC/Kor Ally", "https://api.scryfall.com/cards/tznc/2/en?format=image"); put("ZNC/Rat", "https://api.scryfall.com/cards/tznc/6/en?format=image"); @@ -596,7 +581,6 @@ public class ScryfallImageSupportTokens { put("C21/Beast/1", "https://api.scryfall.com/cards/tc21/10/en?format=image"); // 3/3 put("C21/Beast/2", "https://api.scryfall.com/cards/tc21/11/en?format=image"); // 4/4 put("C21/Boar", "https://api.scryfall.com/cards/tc21/12/en?format=image"); - put("C21/Champion of Wits", "https://api.scryfall.com/cards/tc21/6/en?format=image"); put("C21/Construct/1", "https://api.scryfall.com/cards/tc21/22/en?format=image"); // x/x put("C21/Construct/2", "https://api.scryfall.com/cards/tc21/23/en?format=image"); // 0/0 put("C21/Demon", "https://api.scryfall.com/cards/tc21/7/en?format=image"); @@ -829,17 +813,45 @@ public class ScryfallImageSupportTokens { put("NEC/Thopter", "https://api.scryfall.com/cards/tnec/12/en?format=image"); // SLD + put("SLD/Angel", "https://api.scryfall.com/cards/sld/1340?format=image"); + put("SLD/Cat/1", "https://api.scryfall.com/cards/sld/1517?format=image"); + put("SLD/Cat/2", "https://api.scryfall.com/cards/sld/27?format=image"); + put("SLD/Cat/3", "https://api.scryfall.com/cards/sld/28?format=image"); put("SLD/Clue", "https://api.scryfall.com/cards/sld/348/en?format=image"); + put("SLD/Dog", "https://api.scryfall.com/cards/sld/1516?format=image"); + put("SLD/Egg", "https://api.scryfall.com/cards/sld/1398?format=image"); put("SLD/Faerie Rogue/1", "https://api.scryfall.com/cards/sld/13/en?format=image"); put("SLD/Faerie Rogue/2", "https://api.scryfall.com/cards/sld/14/en?format=image"); put("SLD/Faerie Rogue/3", "https://api.scryfall.com/cards/sld/15/en?format=image"); put("SLD/Faerie Rogue/4", "https://api.scryfall.com/cards/sld/16/en?format=image"); - put("SLD/Treasure", "https://api.scryfall.com/cards/sld/153/en?format=image"); + put("SLD/Food/1", "https://api.scryfall.com/cards/sld/1938?format=image"); + put("SLD/Food/2", "https://api.scryfall.com/cards/sld/2010?format=image"); + put("SLD/Food/3", "https://api.scryfall.com/cards/sld/2011?format=image"); + put("SLD/Food/4", "https://api.scryfall.com/cards/sld/2012?format=image"); + put("SLD/Food/5", "https://api.scryfall.com/cards/sld/2013?format=image"); + put("SLD/Goblin", "https://api.scryfall.com/cards/sld/219?format=image"); + put("SLD/Hydra", "https://api.scryfall.com/cards/sld/1334?format=image"); + put("SLD/Icingdeath, Frost Tongue", "https://api.scryfall.com/cards/sld/1018?format=image"); + put("SLD/Marit Lage", "https://api.scryfall.com/cards/sld/1681?format=image"); + put("SLD/Mechtitan", "https://api.scryfall.com/cards/sld/1969?format=image"); + put("SLD/Saproling", "https://api.scryfall.com/cards/sld/1139?format=image"); + put("SLD/Shrine", "https://api.scryfall.com/cards/sld/1835?format=image"); + put("SLD/Spirit/1", "https://api.scryfall.com/cards/sld/1341?format=image"); + put("SLD/Spirit/2", "https://api.scryfall.com/cards/sld/1852?format=image"); + put("SLD/Squirrel", "https://api.scryfall.com/cards/sld/200?format=image"); + put("SLD/Treasure/1", "https://api.scryfall.com/cards/sld/1432/en?format=image"); + put("SLD/Treasure/2", "https://api.scryfall.com/cards/sld/1736/en?format=image"); + put("SLD/Treasure/3", "https://api.scryfall.com/cards/sld/1507/en?format=image"); + put("SLD/Treasure/4", "https://api.scryfall.com/cards/sld/153/en?format=image"); put("SLD/Walker/1", "https://api.scryfall.com/cards/sld/148/en?format=image"); put("SLD/Walker/2", "https://api.scryfall.com/cards/sld/149/en?format=image"); put("SLD/Walker/3", "https://api.scryfall.com/cards/sld/150/en?format=image"); put("SLD/Walker/4", "https://api.scryfall.com/cards/sld/151/en?format=image"); put("SLD/Walker/5", "https://api.scryfall.com/cards/sld/152/en?format=image"); + put("SLD/Warrior", "https://api.scryfall.com/cards/sld/1752?format=image"); + put("SLD/Wolf", "https://api.scryfall.com/cards/sld/1613?format=image"); + put("SLD/Wurm", "https://api.scryfall.com/cards/sld/1306?format=image"); + put("SLD/Zombie", "https://api.scryfall.com/cards/sld/1357?format=image"); // 2XM put("2XM/Angel", "https://api.scryfall.com/cards/t2xm/3/en?format=image"); @@ -1707,6 +1719,7 @@ public class ScryfallImageSupportTokens { put("CLB/Squid", "https://api.scryfall.com/cards/tclb/29/en?format=image"); put("CLB/Squirrel", "https://api.scryfall.com/cards/tclb/15/en?format=image"); put("CLB/Treasure", "https://api.scryfall.com/cards/tclb/17/en?format=image"); + put("CLB/Undercity", "https://api.scryfall.com/cards/tclb/20/en?format=image"); put("CLB/Volo's Journal", "https://api.scryfall.com/cards/tclb/18/en?format=image"); put("CLB/Warrior", "https://api.scryfall.com/cards/tclb/32/en?format=image"); put("CLB/Emblem Will Kenrith", "https://api.scryfall.com/cards/tclb/50/en?format=image"); @@ -2168,12 +2181,33 @@ public class ScryfallImageSupportTokens { put("WOC/Virtuous", "https://api.scryfall.com/cards/twoc/3/en?format=image"); // WHO + put("WHO/Alien", "https://api.scryfall.com/cards/twho/2?format=image"); put("WHO/Alien Insect", "https://api.scryfall.com/cards/twho/19/en?format=image"); - put("WHO/Human Noble", "https://api.scryfall.com/cards/twho/7/en?format=image"); + put("WHO/Alien Salamander", "https://api.scryfall.com/cards/twho/16?format=image"); + put("WHO/Alien Warrior", "https://api.scryfall.com/cards/twho/14?format=image"); + put("WHO/Beast", "https://api.scryfall.com/cards/twho/17?format=image"); + put("WHO/Clue/1", "https://api.scryfall.com/cards/twho/21?format=image"); + put("WHO/Clue/2", "https://api.scryfall.com/cards/twho/22?format=image"); + put("WHO/Clue/3", "https://api.scryfall.com/cards/twho/23?format=image"); + put("WHO/Dalek", "https://api.scryfall.com/cards/twho/12?format=image"); + put("WHO/Dinosaur", "https://api.scryfall.com/cards/twho/20?format=image"); + put("WHO/Fish", "https://api.scryfall.com/cards/twho/10?format=image"); + put("WHO/Food/1", "https://api.scryfall.com/cards/twho/25?format=image"); + put("WHO/Food/2", "https://api.scryfall.com/cards/twho/26?format=image"); + put("WHO/Food/3", "https://api.scryfall.com/cards/twho/27?format=image"); put("WHO/Horse", "https://api.scryfall.com/cards/twho/4/en?format=image"); + put("WHO/Human", "https://api.scryfall.com/cards/twho/5?format=image"); + put("WHO/Human Noble", "https://api.scryfall.com/cards/twho/7/en?format=image"); + put("WHO/Mark of the Rani", "https://api.scryfall.com/cards/twho/15?format=image"); + put("WHO/Soldier", "https://api.scryfall.com/cards/twho/8?format=image"); + put("WHO/Treasure/1", "https://api.scryfall.com/cards/twho/28?format=image"); + put("WHO/Treasure/2", "https://api.scryfall.com/cards/twho/29?format=image"); + put("WHO/Treasure/3", "https://api.scryfall.com/cards/twho/30?format=image"); + put("WHO/Treasure/4", "https://api.scryfall.com/cards/twho/31?format=image"); + put("WHO/Warrior", "https://api.scryfall.com/cards/twho/9?format=image"); // 8ED - put("8ED/Rukh", "https://api.scryfall.com/cards/p03/7/en?format=image"); + put("8ED/Bird", "https://api.scryfall.com/cards/p03/7/en?format=image"); // LCI put("LCI/Angel", "https://api.scryfall.com/cards/tlci/2/en?format=image"); @@ -2494,7 +2528,18 @@ public class ScryfallImageSupportTokens { put("BLC/Wolf/2", "https://api.scryfall.com/cards/tblc/32/en?format=image"); // DSK + put("DSK/Beast", "https://api.scryfall.com/cards/tdsk/3?format=image"); put("DSK/Emblem Kaito", "https://api.scryfall.com/cards/tdsk/17/en?format=image"); + put("DSK/Everywhere", "https://api.scryfall.com/cards/tdsk/16?format=image"); + put("DSK/Glimmer", "https://api.scryfall.com/cards/tdsk/4?format=image"); + put("DSK/Gremlin", "https://api.scryfall.com/cards/tdsk/11?format=image"); + put("DSK/Insect/1", "https://api.scryfall.com/cards/tdsk/13?format=image"); + put("DSK/Insect/2", "https://api.scryfall.com/cards/tdsk/5?format=image"); + put("DSK/Primo, the Indivisible", "https://api.scryfall.com/cards/tdsk/14?format=image"); + put("DSK/Shard", "https://api.scryfall.com/cards/tdsk/2?format=image"); + put("DSK/Spider", "https://api.scryfall.com/cards/tdsk/12?format=image"); + put("DSK/Spirit", "https://api.scryfall.com/cards/tdsk/8?format=image"); + put("DSK/Treasure", "https://api.scryfall.com/cards/tdsk/15?format=image"); // DSC put("DSC/Angel", "https://api.scryfall.com/cards/tdsc/2/en?format=image"); @@ -2615,20 +2660,43 @@ public class ScryfallImageSupportTokens { put("DRC/Zombie Army", "https://api.scryfall.com/cards/tdrc/8/en?format=image"); put("DRC/Zombie Warrior", "https://api.scryfall.com/cards/tdrc/9/en?format=image"); + // TDM + put("TDM/Bird", "https://api.scryfall.com/cards/ttdm/2/en?format=image"); + put("TDM/Dragon", "https://api.scryfall.com/cards/ttdm/11/en?format=image"); + put("TDM/Elephant", "https://api.scryfall.com/cards/ttdm/14/en?format=image"); + put("TDM/Goblin", "https://api.scryfall.com/cards/ttdm/12/en?format=image"); + put("TDM/Monk", "https://api.scryfall.com/cards/ttdm/3/en?format=image"); + put("TDM/Reliquary Dragon", "https://api.scryfall.com/cards/ttdm/15/en?format=image"); + put("TDM/Soldier/1", "https://api.scryfall.com/cards/ttdm/4/en?format=image"); + put("TDM/Soldier/2", "https://api.scryfall.com/cards/ttdm/5/en?format=image"); + put("TDM/Spirit/1", "https://api.scryfall.com/cards/ttdm/9/en?format=image"); + put("TDM/Spirit/2", "https://api.scryfall.com/cards/ttdm/6/en?format=image"); + // TODO: 2/2 and 3/3 Spirit tokens (no relevant cards revealed, token not implemented) + put("TDM/Treasure", "https://api.scryfall.com/cards/ttdm/16/en?format=image"); + put("TDM/Warrior", "https://api.scryfall.com/cards/ttdm/13/en?format=image"); + put("TDM/Zombie Druid", "https://api.scryfall.com/cards/ttdm/10/en?format=image"); + // TDC put("TDC/Angel", "https://api.scryfall.com/cards/ttdc/2/en?format=image"); + put("TDC/Beast", "https://api.scryfall.com/cards/ttdc/20?format=image"); put("TDC/Citizen", "https://api.scryfall.com/cards/ttdc/26/en?format=image"); put("TDC/Dog", "https://api.scryfall.com/cards/ttdc/3/en?format=image"); + put("TDC/Dragon/1", "https://api.scryfall.com/cards/ttdc/13?format=image"); + put("TDC/Dragon/2", "https://api.scryfall.com/cards/ttdc/14?format=image"); + put("TDC/Dragon Egg", "https://api.scryfall.com/cards/ttdc/12?format=image"); put("TDC/Dragon Illusion", "https://api.scryfall.com/cards/ttdc/15/en?format=image"); put("TDC/Eldrazi", "https://api.scryfall.com/cards/ttdc/1/en?format=image"); put("TDC/Elemental/1", "https://api.scryfall.com/cards/ttdc/16/en?format=image"); put("TDC/Elemental/2", "https://api.scryfall.com/cards/ttdc/17/en?format=image"); put("TDC/Elemental/3", "https://api.scryfall.com/cards/ttdc/27/en?format=image"); put("TDC/First Mate Ragavan", "https://api.scryfall.com/cards/ttdc/18/en?format=image"); + put("TDC/Frog Lizard", "https://api.scryfall.com/cards/ttdc/21?format=image"); put("TDC/Goat", "https://api.scryfall.com/cards/ttdc/4/en?format=image"); put("TDC/Gold", "https://api.scryfall.com/cards/ttdc/29/en?format=image"); put("TDC/Human", "https://api.scryfall.com/cards/ttdc/5/en?format=image"); + put("TDC/Inkling", "https://api.scryfall.com/cards/ttdc/28?format=image"); put("TDC/Insect", "https://api.scryfall.com/cards/ttdc/22/en?format=image"); + put("TDC/Karox Bladewing", "https://api.scryfall.com/cards/ttdc/19?format=image"); put("TDC/Myr", "https://api.scryfall.com/cards/ttdc/30/en?format=image"); put("TDC/Plant", "https://api.scryfall.com/cards/ttdc/24/en?format=image"); put("TDC/Rat", "https://api.scryfall.com/cards/ttdc/9/en?format=image"); @@ -2636,9 +2704,136 @@ public class ScryfallImageSupportTokens { put("TDC/Servo", "https://api.scryfall.com/cards/ttdc/31/en?format=image"); put("TDC/Snake", "https://api.scryfall.com/cards/ttdc/10/en?format=image"); put("TDC/Soldier", "https://api.scryfall.com/cards/ttdc/32/en?format=image"); + put("TDC/Spider", "https://api.scryfall.com/cards/ttdc/25?format=image"); put("TDC/Spirit", "https://api.scryfall.com/cards/ttdc/6/en?format=image"); put("TDC/Thopter", "https://api.scryfall.com/cards/ttdc/33/en?format=image"); + // ACR + put("ACR/Assassin", "https://api.scryfall.com/cards/tacr/4?format=image"); + put("ACR/Emblem Capitoline Triad", "https://api.scryfall.com/cards/tacr/7/en?format=image"); + put("ACR/Human Rogue", "https://api.scryfall.com/cards/tacr/3?format=image"); + put("ACR/Phobos", "https://api.scryfall.com/cards/tacr/5?format=image"); + put("ACR/Shapeshifter", "https://api.scryfall.com/cards/tacr/2?format=image"); + put("ACR/Treasure", "https://api.scryfall.com/cards/tacr/6?format=image"); + + // DD2 + put("DD2/Elemental Shaman", "https://api.scryfall.com/cards/tdd2/1?format=image"); + + // FIN + put("FIN/Food", "https://api.scryfall.com/cards/tfin/22?format=image"); + + // JVC + put("JVC/Elemental Shaman", "https://api.scryfall.com/cards/tjvc/4?format=image"); + + // PIP + put("PIP/Alien", "https://api.scryfall.com/cards/tpip/6?format=image"); + put("PIP/Clue", "https://api.scryfall.com/cards/tpip/11?format=image"); + put("PIP/Food/1", "https://api.scryfall.com/cards/tpip/12?format=image"); + put("PIP/Food/2", "https://api.scryfall.com/cards/tpip/13?format=image"); + put("PIP/Food/3", "https://api.scryfall.com/cards/tpip/14?format=image"); + put("PIP/Human Knight", "https://api.scryfall.com/cards/tpip/2?format=image"); + put("PIP/Human Soldier", "https://api.scryfall.com/cards/tpip/3?format=image"); + put("PIP/Junk", "https://api.scryfall.com/cards/tpip/15?format=image"); + put("PIP/Robot", "https://api.scryfall.com/cards/tpip/16?format=image"); + put("PIP/Settlement", "https://api.scryfall.com/cards/tpip/8?format=image"); + put("PIP/Soldier/1", "https://api.scryfall.com/cards/tpip/10?format=image"); + put("PIP/Soldier/2", "https://api.scryfall.com/cards/tpip/4?format=image"); + put("PIP/Squirrel", "https://api.scryfall.com/cards/tpip/9?format=image"); + put("PIP/Thopter", "https://api.scryfall.com/cards/tpip/17?format=image"); + put("PIP/Treasure/1", "https://api.scryfall.com/cards/tpip/18?format=image"); + put("PIP/Treasure/2", "https://api.scryfall.com/cards/tpip/19?format=image"); + put("PIP/Warrior", "https://api.scryfall.com/cards/tpip/5?format=image"); + put("PIP/Wasteland Survival Guide", "https://api.scryfall.com/cards/tpip/20?format=image"); + put("PIP/Zombie Mutant", "https://api.scryfall.com/cards/tpip/7?format=image"); + + // REX + put("REX/Dinosaur", "https://api.scryfall.com/cards/trex/1?format=image"); + put("REX/Treasure", "https://api.scryfall.com/cards/trex/2?format=image"); + + // UGL + put("UGL/Goblin", "https://api.scryfall.com/cards/tugl/4?format=image"); + put("UGL/Pegasus", "https://api.scryfall.com/cards/tugl/1?format=image"); + put("UGL/Soldier", "https://api.scryfall.com/cards/tugl/2?format=image"); + put("UGL/Squirrel", "https://api.scryfall.com/cards/tugl/6?format=image"); + put("UGL/Zombie", "https://api.scryfall.com/cards/tugl/3?format=image"); + + // UST + put("UST/Angel", "https://api.scryfall.com/cards/tust/1?format=image"); + put("UST/Beast", "https://api.scryfall.com/cards/tust/13?format=image"); + put("UST/Brainiac", "https://api.scryfall.com/cards/tust/10?format=image"); + put("UST/Clue", "https://api.scryfall.com/cards/tust/18?format=image"); + put("UST/Dragon", "https://api.scryfall.com/cards/tust/16?format=image"); + put("UST/Elemental/1", "https://api.scryfall.com/cards/tust/11?format=image"); + put("UST/Elemental/2", "https://api.scryfall.com/cards/tust/17?format=image"); + put("UST/Gnome", "https://api.scryfall.com/cards/tust/20?format=image"); + put("UST/Goat", "https://api.scryfall.com/cards/tust/2?format=image"); + put("UST/Goblin", "https://api.scryfall.com/cards/tust/12?format=image"); + put("UST/Saproling", "https://api.scryfall.com/cards/tust/14?format=image"); + put("UST/Spirit", "https://api.scryfall.com/cards/tust/3?format=image"); + put("UST/Squirrel", "https://api.scryfall.com/cards/tust/15?format=image"); + put("UST/Storm Crow", "https://api.scryfall.com/cards/tust/5?format=image"); + put("UST/Thopter", "https://api.scryfall.com/cards/tust/6?format=image"); + put("UST/Vampire", "https://api.scryfall.com/cards/tust/8?format=image"); + put("UST/Zombie", "https://api.scryfall.com/cards/tust/9?format=image"); + + // F12 + put("F12/Human", "https://api.scryfall.com/cards/f12/1a?format=image"); + put("F12/Wolf", "https://api.scryfall.com/cards/f12/1a?format=image&face=back"); + + // F17 + put("F17/Dinosaur", "https://api.scryfall.com/cards/f17/11?format=image"); + put("F17/Pirate", "https://api.scryfall.com/cards/f17/12?format=image"); + put("F17/Vampire", "https://api.scryfall.com/cards/f17/10?format=image"); + put("F17/Treasure/1", "https://api.scryfall.com/cards/f17/11?format=image&face=back"); + put("F17/Treasure/2", "https://api.scryfall.com/cards/f17/12?format=image&face=back"); + put("F17/Treasure/3", "https://api.scryfall.com/cards/f17/10?format=image&face=back"); + + // HHO + put("HHO/Treasure", "https://api.scryfall.com/cards/hho/21★?format=image"); + + // J12 + put("J12/Centaur", "https://api.scryfall.com/cards/j12/9?format=image"); + + // J13 + put("J13/Golem", "https://api.scryfall.com/cards/j13/9?format=image"); + + // MPR + put("MPR/Bear", "https://api.scryfall.com/cards/mpr/7?format=image"); + put("MPR/Beast", "https://api.scryfall.com/cards/mpr/8?format=image"); + put("MPR/Bird", "https://api.scryfall.com/cards/mpr/4?format=image"); + put("MPR/Elephant", "https://api.scryfall.com/cards/mpr/3?format=image"); + put("MPR/Goblin Soldier", "https://api.scryfall.com/cards/mpr/6?format=image"); + put("MPR/Saproling", "https://api.scryfall.com/cards/mpr/2?format=image"); + put("MPR/Spirit", "https://api.scryfall.com/cards/mpr/5?format=image"); + + // P03 + put("P03/Bear", "https://api.scryfall.com/cards/p03/4?format=image"); + put("P03/Demon", "https://api.scryfall.com/cards/p03/6?format=image"); + put("P03/Goblin", "https://api.scryfall.com/cards/p03/5?format=image"); + put("P03/Insect", "https://api.scryfall.com/cards/p03/2?format=image"); + put("P03/Bird", "https://api.scryfall.com/cards/p03/7?format=image"); + put("P03/Sliver", "https://api.scryfall.com/cards/p03/3?format=image"); + + // P04 + put("P04/Angel", "https://api.scryfall.com/cards/p04/2?format=image"); + put("P04/Beast", "https://api.scryfall.com/cards/p04/5?format=image"); + put("P04/Myr", "https://api.scryfall.com/cards/p04/4?format=image"); + put("P04/Pentavite", "https://api.scryfall.com/cards/p04/3?format=image"); + put("P04/Spirit", "https://api.scryfall.com/cards/p04/6?format=image"); + + // PEMN + put("PEMN/Zombie/1", "https://api.scryfall.com/cards/pemn/1Z?format=image"); + put("PEMN/Zombie/2", "https://api.scryfall.com/cards/pemn/1Z?format=image&face=back"); + + // PHEL + put("PHEL/Angel", "https://api.scryfall.com/cards/phel/1★?format=image"); + + // PL21 + put("PL21/Minotaur", "https://api.scryfall.com/cards/pl21/2★?format=image"); + + // PL23 + put("PL23/Food", "https://api.scryfall.com/cards/pl23/2?format=image"); + // generate supported sets supportedSets.clear(); for (String cardName : this.keySet()) { diff --git a/Mage.Client/src/test/java/mage/client/game/ScryfallImagesDownloadTest.java b/Mage.Client/src/test/java/mage/client/game/ScryfallImagesDownloadTest.java index 003db308954..25b1455fe36 100644 --- a/Mage.Client/src/test/java/mage/client/game/ScryfallImagesDownloadTest.java +++ b/Mage.Client/src/test/java/mage/client/game/ScryfallImagesDownloadTest.java @@ -43,7 +43,7 @@ public class ScryfallImagesDownloadTest { .anyMatch(c -> c.getCardNumber().equals("001")) ); urls = imageSource.generateCardUrl(new CardDownloadData("The One Ring", "LTR", "001", false, 0)); - Assert.assertEquals("https://api.scryfall.com/cards/ltr/0/en?format=image", urls.getBaseUrl()); + Assert.assertEquals("https://api.scryfall.com/cards/ltr/0/qya?format=image", urls.getBaseUrl()); // added same tests for small images @@ -74,6 +74,6 @@ public class ScryfallImagesDownloadTest { .anyMatch(c -> c.getCardNumber().equals("001")) ); urls = imageSourceSmall.generateCardUrl(new CardDownloadData("The One Ring", "LTR", "001", false, 0)); - Assert.assertEquals("https://api.scryfall.com/cards/ltr/0/en?format=image&version=small", urls.getBaseUrl()); + Assert.assertEquals("https://api.scryfall.com/cards/ltr/0/qya?format=image&version=small", urls.getBaseUrl()); } } diff --git a/Mage.Common/src/main/java/mage/view/CombatGroupView.java b/Mage.Common/src/main/java/mage/view/CombatGroupView.java index e8fc7449d8d..c757ad6ff0d 100644 --- a/Mage.Common/src/main/java/mage/view/CombatGroupView.java +++ b/Mage.Common/src/main/java/mage/view/CombatGroupView.java @@ -40,7 +40,7 @@ public class CombatGroupView implements Serializable { attackers.put(id, new PermanentView(attacker, game.getCard(attacker.getId()),null, game)); } } - for (UUID id: combatGroup.getBlockerOrder()) { + for (UUID id: combatGroup.getBlockers()) { Permanent blocker = game.getPermanent(id); if (blocker != null) { blockers.put(id, new PermanentView(blocker, game.getCard(blocker.getId()), null, game)); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Legacy.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Legacy.java index a0dfd0d541b..a75071e26b9 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Legacy.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Legacy.java @@ -64,6 +64,7 @@ public class Legacy extends Constructed { banned.add("Sensei's Divining Top"); banned.add("Skullclamp"); banned.add("Sol Ring"); + banned.add("Sowing Mycospawn"); banned.add("Strip Mine"); banned.add("Survival of the Fittest"); banned.add("Time Vault"); @@ -72,6 +73,7 @@ public class Legacy extends Constructed { banned.add("Tinker"); banned.add("Tolarian Academy"); banned.add("Treasure Cruise"); + banned.add("Troll of Khazad-dum"); banned.add("Underworld Breach"); banned.add("Vampiric Tutor"); banned.add("Vexing Bauble"); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Modern.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Modern.java index f079385508e..cb7a5fa939c 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Modern.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Modern.java @@ -69,6 +69,7 @@ public class Modern extends Constructed { banned.add("Treasure Cruise"); banned.add("Tree of Tales"); banned.add("Umezawa's Jitte"); + banned.add("Underworld Breach"); banned.add("Up the Beanstalk"); banned.add("Uro, Titan of Nature's Wrath"); banned.add("Vault of Whispers"); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java index e7ec4d300ce..6dbba75643f 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java @@ -29,6 +29,7 @@ public class Pauper extends Constructed { banned.add("All That Glitters"); banned.add("Arcum's Astrolabe"); banned.add("Atog"); + banned.add("Basking Broodscale"); banned.add("Bonder's Ornament"); banned.add("Chatterstorm"); banned.add("Cloud of Faeries"); @@ -36,6 +37,7 @@ public class Pauper extends Constructed { banned.add("Cranial Plating"); banned.add("Cranial Ram"); banned.add("Daze"); + banned.add("Deadly Dispute"); banned.add("Disciple of the Vault"); banned.add("Empty the Warrens"); banned.add("Fall from Favor"); @@ -44,13 +46,12 @@ public class Pauper extends Constructed { banned.add("Gitaxian Probe"); banned.add("Grapeshot"); banned.add("Gush"); - banned.add("High Tide"); banned.add("Hymn to Tourach"); banned.add("Invigorate"); + banned.add("Kuldotha Rebirth"); banned.add("Monastery Swiftspear"); banned.add("Mystic Sanctuary"); banned.add("Peregrine Drake"); - banned.add("Prophetic Prism"); banned.add("Sinkhole"); banned.add("Stirring Bard"); banned.add("Sojourner's Companion"); diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayerControllableProxy.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayerControllableProxy.java index dd63da4bdf0..e03ed1d623f 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayerControllableProxy.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayerControllableProxy.java @@ -13,10 +13,8 @@ import mage.constants.MultiAmountType; import mage.constants.Outcome; import mage.constants.RangeOfInfluence; import mage.game.Game; -import mage.game.combat.CombatGroup; import mage.game.draft.Draft; import mage.game.match.Match; -import mage.game.permanent.Permanent; import mage.game.tournament.Tournament; import mage.players.Player; import mage.target.Target; @@ -287,24 +285,6 @@ public class ComputerPlayerControllableProxy extends ComputerPlayer7 { } } - @Override - public UUID chooseAttackerOrder(java.util.List attackers, Game game) { - if (isUnderMe(game)) { - return super.chooseAttackerOrder(attackers, game); - } else { - return getControllingPlayer(game).chooseAttackerOrder(attackers, game); - } - } - - @Override - public UUID chooseBlockerOrder(java.util.List blockers, CombatGroup combatGroup, java.util.List blockerOrder, Game game) { - if (isUnderMe(game)) { - return super.chooseBlockerOrder(blockers, combatGroup, blockerOrder, game); - } else { - return getControllingPlayer(game).chooseBlockerOrder(blockers, combatGroup, blockerOrder, game); - } - } - @Override public int getAmount(int min, int max, String message, Game game) { if (isUnderMe(game)) { diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index a938ef24827..d21ecf58811 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -2177,9 +2177,6 @@ public class ComputerPlayer extends PlayerImpl { // TODO: add AI support with outcome and replace random with min/max public int getAmount(int min, int max, String message, Game game) { log.debug("getAmount"); - if (message.startsWith("Assign damage to ")) { - return min; - } if (min < max && min == 0) { return RandomUtil.nextInt(CardUtil.overflowInc(max, 1)); } @@ -2192,7 +2189,7 @@ public class ComputerPlayer extends PlayerImpl { log.debug("getMultiAmount"); int needCount = messages.size(); - List defaultList = MultiAmountType.prepareDefaltValues(messages, totalMin, totalMax); + List defaultList = MultiAmountType.prepareDefaultValues(messages, totalMin, totalMax); if (needCount == 0) { return defaultList; } @@ -2210,18 +2207,6 @@ public class ComputerPlayer extends PlayerImpl { return MultiAmountType.prepareMaxValues(messages, totalMin, totalMax); } - @Override - public UUID chooseAttackerOrder(List attackers, Game game) { - //TODO: improve this - return attackers.iterator().next().getId(); - } - - @Override - public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, List blockerOrder, Game game) { - //TODO: improve this - return blockers.iterator().next().getId(); - } - @Override public List getAvailableManaProducers(Game game) { return super.getAvailableManaProducers(game); diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java index 3bb1a34df10..5fd1b4ea3b2 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java @@ -374,22 +374,6 @@ public final class SimulatedPlayerMCTS extends MCTSPlayer { return super.chooseMode(modes, source, game); } - @Override - public UUID chooseAttackerOrder(List attackers, Game game) { - if (this.isHuman()) { - return attackers.get(RandomUtil.nextInt(attackers.size())).getId(); - } - return super.chooseAttackerOrder(attackers, game); - } - - @Override - public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, List blockerOrder, Game game) { - if (this.isHuman()) { - return blockers.get(RandomUtil.nextInt(blockers.size())).getId(); - } - return super.chooseBlockerOrder(blockers, combatGroup, blockerOrder, game); - } - @Override public int getAmount(int min, int max, String message, Game game) { if (this.isHuman()) { diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index f35221b49eb..f035a45fe6b 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -2122,56 +2122,6 @@ public class HumanPlayer extends PlayerImpl { } } - @Override - public UUID chooseAttackerOrder(java.util.List attackers, Game game) { - if (gameInCheckPlayableState(game)) { - return null; - } - - while (canRespond()) { - prepareForResponse(game); - if (!isExecutingMacro()) { - game.fireSelectTargetEvent(playerId, "Pick attacker", attackers, true); - } - waitForResponse(game); - - UUID responseId = getFixedResponseUUID(game); - if (responseId != null) { - for (Permanent perm : attackers) { - if (perm.getId().equals(responseId)) { - return perm.getId(); - } - } - } - } - return null; - } - - @Override - public UUID chooseBlockerOrder(java.util.List blockers, CombatGroup combatGroup, java.util.List blockerOrder, Game game) { - if (gameInCheckPlayableState(game)) { - return null; - } - - while (canRespond()) { - prepareForResponse(game); - if (!isExecutingMacro()) { - game.fireSelectTargetEvent(playerId, "Pick blocker", blockers, true); - } - waitForResponse(game); - - UUID responseId = getFixedResponseUUID(game); - if (responseId != null) { - for (Permanent perm : blockers) { - if (perm.getId().equals(responseId)) { - return perm.getId(); - } - } - } - } - return null; - } - protected void selectCombatGroup(UUID defenderId, UUID blockerId, Game game) { if (gameInCheckPlayableState(game)) { return; @@ -2260,7 +2210,7 @@ public class HumanPlayer extends PlayerImpl { Game game ) { int needCount = messages.size(); - List defaultList = MultiAmountType.prepareDefaltValues(messages, totalMin, totalMax); + List defaultList = MultiAmountType.prepareDefaultValues(messages, totalMin, totalMax); if (needCount == 0 || (needCount == 1 && totalMin == totalMax) || messages.stream().map(m -> m.min == m.max).reduce(true, Boolean::logicalAnd)) { // nothing to choose diff --git a/Mage.Sets/src/mage/cards/a/AdornedCrocodile.java b/Mage.Sets/src/mage/cards/a/AdornedCrocodile.java new file mode 100644 index 00000000000..e50e57f63db --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AdornedCrocodile.java @@ -0,0 +1,43 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.RenewAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.game.permanent.token.ZombieDruidToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AdornedCrocodile extends CardImpl { + + public AdornedCrocodile(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.subtype.add(SubType.CROCODILE); + this.power = new MageInt(5); + this.toughness = new MageInt(3); + + // When this creature dies, create a 2/2 black Zombie Druid creature token. + this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new ZombieDruidToken()))); + + // Renew -- {B}, Exile this card from your graveyard: Put a +1/+1 counter on target creature. Activate only as a sorcery. + this.addAbility(new RenewAbility("{B}", CounterType.P1P1.createInstance())); + } + + private AdornedCrocodile(final AdornedCrocodile card) { + super(card); + } + + @Override + public AdornedCrocodile copy() { + return new AdornedCrocodile(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AinokWayfarer.java b/Mage.Sets/src/mage/cards/a/AinokWayfarer.java new file mode 100644 index 00000000000..77f093dc213 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AinokWayfarer.java @@ -0,0 +1,44 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.MillThenPutInHandEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AinokWayfarer extends CardImpl { + + public AinokWayfarer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.DOG); + this.subtype.add(SubType.SCOUT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // When this creature enters, mill three cards. You may put a land card from among them into your hand. If you don't, put a +1/+1 counter on this creature. + this.addAbility(new EntersBattlefieldTriggeredAbility(new MillThenPutInHandEffect( + 1, StaticFilters.FILTER_CARD_LAND_A, + new AddCountersSourceEffect(CounterType.P1P1.createInstance(), true) + ))); + } + + private AinokWayfarer(final AinokWayfarer card) { + super(card); + } + + @Override + public AinokWayfarer copy() { + return new AinokWayfarer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AlchemistsAssistant.java b/Mage.Sets/src/mage/cards/a/AlchemistsAssistant.java new file mode 100644 index 00000000000..9681199b1be --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AlchemistsAssistant.java @@ -0,0 +1,41 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.RenewAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AlchemistsAssistant extends CardImpl { + + public AlchemistsAssistant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.MONKEY); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // Renew -- {1}{B}, Exile this card from your graveyard: Put a lifelink counter on target creature. Activate only as a sorcery. + this.addAbility(new RenewAbility("{1}{B}", CounterType.LIFELINK.createInstance())); + } + + private AlchemistsAssistant(final AlchemistsAssistant card) { + super(card); + } + + @Override + public AlchemistsAssistant copy() { + return new AlchemistsAssistant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArashinSunshield.java b/Mage.Sets/src/mage/cards/a/ArashinSunshield.java new file mode 100644 index 00000000000..3ea6618a2aa --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArashinSunshield.java @@ -0,0 +1,54 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInASingleGraveyard; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArashinSunshield extends CardImpl { + + public ArashinSunshield(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // When this creature enters, exile up to two target cards from a single graveyard. + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetEffect()); + ability.addTarget(new TargetCardInASingleGraveyard(0, 2, StaticFilters.FILTER_CARDS_NON_LAND)); + this.addAbility(ability); + + // {W}, {T}: Tap target creature. + ability = new SimpleActivatedAbility(new TapTargetEffect(), new ManaCostsImpl<>("{W}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private ArashinSunshield(final ArashinSunshield card) { + super(card); + } + + @Override + public ArashinSunshield copy() { + return new ArashinSunshield(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java b/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java index 4b922159db5..55a1fcc34b2 100644 --- a/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java +++ b/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java @@ -153,10 +153,6 @@ class BalduvianWarlordUnblockEffect extends OneShotEffect { game.fireEvent(new BlockerDeclaredEvent(chosenPermanent.getId(), permanent.getId(), permanent.getControllerId())); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKS, permanent.getId(), source, null)); } - CombatGroup blockGroup = findBlockingGroup(permanent, game); // a new blockingGroup is formed, so it's necessary to find it again - if (blockGroup != null) { - blockGroup.pickAttackerOrder(permanent.getControllerId(), game); - } } } return true; @@ -164,15 +160,4 @@ class BalduvianWarlordUnblockEffect extends OneShotEffect { } return false; } - - private CombatGroup findBlockingGroup(Permanent blocker, Game game) { - if (game.getCombat().blockingGroupsContains(blocker.getId())) { // if (blocker.getBlocking() > 1) { - for (CombatGroup group : game.getCombat().getBlockingGroups()) { - if (group.getBlockers().contains(blocker.getId())) { - return group; - } - } - } - return null; - } } diff --git a/Mage.Sets/src/mage/cards/b/BrimazKingOfOreskos.java b/Mage.Sets/src/mage/cards/b/BrimazKingOfOreskos.java index 2e78b4dd69a..cdec812d778 100644 --- a/Mage.Sets/src/mage/cards/b/BrimazKingOfOreskos.java +++ b/Mage.Sets/src/mage/cards/b/BrimazKingOfOreskos.java @@ -1,7 +1,6 @@ package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; @@ -22,6 +21,8 @@ import mage.game.permanent.token.CatSoldierCreatureToken; import mage.game.permanent.token.Token; import mage.players.Player; +import java.util.UUID; + /** * * @author LevelX2 @@ -99,7 +100,6 @@ class BrimazKingOfOreskosEffect extends OneShotEffect { combatGroup.addBlocker(tokenId, source.getControllerId(), game); game.getCombat().addBlockingGroup(tokenId, attackingCreature.getId(), controller.getId(), game); } - combatGroup.pickBlockerOrder(attackingCreature.getControllerId(), game); return true; } diff --git a/Mage.Sets/src/mage/cards/c/ChampionOfDusan.java b/Mage.Sets/src/mage/cards/c/ChampionOfDusan.java new file mode 100644 index 00000000000..ab384f74f2b --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChampionOfDusan.java @@ -0,0 +1,46 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.RenewAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ChampionOfDusan extends CardImpl { + + public ChampionOfDusan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Renew -- {1}{G}, Exile this card from your graveyard: Put a +1/+1 counter and a trample counter on target creature. Activate only as a sorcery. + this.addAbility(new RenewAbility( + "{1}{G}", + CounterType.P1P1.createInstance(), + CounterType.TRAMPLE.createInstance() + )); + } + + private ChampionOfDusan(final ChampionOfDusan card) { + super(card); + } + + @Override + public ChampionOfDusan copy() { + return new ChampionOfDusan(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ConstrictorSage.java b/Mage.Sets/src/mage/cards/c/ConstrictorSage.java new file mode 100644 index 00000000000..57429482fc1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ConstrictorSage.java @@ -0,0 +1,59 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.ExileSourceFromGraveCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ConstrictorSage extends CardImpl { + + public ConstrictorSage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.subtype.add(SubType.SNAKE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // When this creature enters, tap target creature an opponent controls and put a stun counter on it. + Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); + ability.addEffect(new AddCountersTargetEffect(CounterType.STUN.createInstance()) + .setText("and put a stun counter on it")); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + + // Renew -- {2}{U}, Exile this card from your graveyard: Tap target creature an opponent controls and put a stun counter on it. Activate only as a sorcery. + ability = new ActivateAsSorceryActivatedAbility(Zone.GRAVEYARD, new TapTargetEffect(), new ManaCostsImpl<>("{2}{U}")); + ability.addCost(new ExileSourceFromGraveCost()); + ability.addEffect(new AddCountersTargetEffect(CounterType.STUN.createInstance()) + .setText("and put a stun counter on it")); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability.setAbilityWord(AbilityWord.RENEW)); + } + + private ConstrictorSage(final ConstrictorSage card) { + super(card); + } + + @Override + public ConstrictorSage copy() { + return new ConstrictorSage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CrushOfTentacles.java b/Mage.Sets/src/mage/cards/c/CrushOfTentacles.java index 933d08d7330..2e2f579b3c0 100644 --- a/Mage.Sets/src/mage/cards/c/CrushOfTentacles.java +++ b/Mage.Sets/src/mage/cards/c/CrushOfTentacles.java @@ -12,7 +12,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterNonlandPermanent; -import mage.game.permanent.token.CrushOfTentaclesToken; +import mage.game.permanent.token.OctopusToken; /** * @@ -25,7 +25,7 @@ public final class CrushOfTentacles extends CardImpl { // Return all nonland permanents to their owners' hands. If Crush of Tentacles surge cost was paid, create an 8/8 blue Octopus creature token. getSpellAbility().addEffect(new ReturnToHandFromBattlefieldAllEffect(new FilterNonlandPermanent("nonland permanents"))); - Effect effect = new ConditionalOneShotEffect(new CreateTokenEffect(new CrushOfTentaclesToken()), SurgedCondition.instance); + Effect effect = new ConditionalOneShotEffect(new CreateTokenEffect(new OctopusToken()), SurgedCondition.instance); effect.setText("If this spell's surge cost was paid, create an 8/8 blue Octopus creature token"); getSpellAbility().addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/d/DanceOfTheTumbleweeds.java b/Mage.Sets/src/mage/cards/d/DanceOfTheTumbleweeds.java index 9a158a24685..0d6f28edb95 100644 --- a/Mage.Sets/src/mage/cards/d/DanceOfTheTumbleweeds.java +++ b/Mage.Sets/src/mage/cards/d/DanceOfTheTumbleweeds.java @@ -17,7 +17,7 @@ import mage.constants.SuperType; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.game.Game; -import mage.game.permanent.token.SeedGuardianToken; +import mage.game.permanent.token.ElementalXXGreenToken; import mage.target.common.TargetCardInLibrary; import java.util.UUID; @@ -83,7 +83,7 @@ class DanceOfTheTumbleweedsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - return new SeedGuardianToken(LandsYouControlCount.instance.calculate(game, source, this)) + return new ElementalXXGreenToken(LandsYouControlCount.instance.calculate(game, source, this)) .putOntoBattlefield(1, game, source); } } diff --git a/Mage.Sets/src/mage/cards/d/DragonSniper.java b/Mage.Sets/src/mage/cards/d/DragonSniper.java new file mode 100644 index 00000000000..336d59958f4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DragonSniper.java @@ -0,0 +1,45 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.ReachAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DragonSniper extends CardImpl { + + public DragonSniper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ARCHER); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + } + + private DragonSniper(final DragonSniper card) { + super(card); + } + + @Override + public DragonSniper copy() { + return new DragonSniper(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ElspethStormSlayer.java b/Mage.Sets/src/mage/cards/e/ElspethStormSlayer.java new file mode 100644 index 00000000000..cbf61ff0f3a --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ElspethStormSlayer.java @@ -0,0 +1,74 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.abilities.effects.common.replacement.CreateTwiceThatManyTokensEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterOpponentsCreaturePermanent; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.permanent.token.SoldierToken; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ElspethStormSlayer extends CardImpl { + + private static final FilterPermanent filter + = new FilterOpponentsCreaturePermanent("creature an opponent controls with mana value 3 or greater"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.MORE_THAN, 2)); + } + + public ElspethStormSlayer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}{W}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.ELSPETH); + this.setStartingLoyalty(5); + + // If one or more tokens would be created under your control, twice that many of those tokens are created instead. + this.addAbility(new SimpleStaticAbility(new CreateTwiceThatManyTokensEffect())); + + // +1: Create a 1/1 white Soldier creature token. + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new SoldierToken()), 1)); + + // 0: Put a +1/+1 counter on each creature you control. Those creatures gain flying until your next turn. + Ability ability = new LoyaltyAbility(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE + ), 0); + ability.addEffect(new GainAbilityControlledEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("those creatures gain flying until end of turn")); + this.addAbility(ability); + + // -3: Destroy target creature an opponent controls with mana value 3 or greater. + ability = new LoyaltyAbility(new DestroyTargetEffect(), -3); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private ElspethStormSlayer(final ElspethStormSlayer card) { + super(card); + } + + @Override + public ElspethStormSlayer copy() { + return new ElspethStormSlayer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EssenceAnchor.java b/Mage.Sets/src/mage/cards/e/EssenceAnchor.java new file mode 100644 index 00000000000..503512b1615 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EssenceAnchor.java @@ -0,0 +1,64 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.Game; +import mage.game.permanent.token.ZombieDruidToken; +import mage.watchers.common.CardsLeftGraveyardWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EssenceAnchor extends CardImpl { + + public EssenceAnchor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{U}"); + + // At the beginning of your upkeep, surveil 1. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SurveilEffect(1))); + + // {T}: Create a 2/2 black Zombie Druid creature token. Activate only during your turn and only if a card left your graveyard this turn. + this.addAbility(new ActivateIfConditionActivatedAbility( + new CreateTokenEffect(new ZombieDruidToken()), + new TapSourceCost(), EssenceAnchorCondition.instance + ), new CardsLeftGraveyardWatcher()); + } + + private EssenceAnchor(final EssenceAnchor card) { + super(card); + } + + @Override + public EssenceAnchor copy() { + return new EssenceAnchor(this); + } +} + +enum EssenceAnchorCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return game.isActivePlayer(source.getControllerId()) + && !game + .getState() + .getWatcher(CardsLeftGraveyardWatcher.class) + .getCardsThatLeftGraveyard(source.getControllerId(), game) + .isEmpty(); + } + + @Override + public String toString() { + return "during your turn and only if a card left your graveyard this turn"; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EyesOfTheWisent.java b/Mage.Sets/src/mage/cards/e/EyesOfTheWisent.java index 5da9e6b315e..4a97eda2c78 100644 --- a/Mage.Sets/src/mage/cards/e/EyesOfTheWisent.java +++ b/Mage.Sets/src/mage/cards/e/EyesOfTheWisent.java @@ -12,7 +12,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.FilterSpell; import mage.filter.predicate.mageobject.ColorPredicate; -import mage.game.permanent.token.EyesOfTheWisentElementalToken; +import mage.game.permanent.token.Elemental44GreenToken; import java.util.UUID; @@ -33,7 +33,7 @@ public final class EyesOfTheWisent extends CardImpl { // Whenever an opponent casts a blue spell during your turn, you may create a 4/4 green Elemental creature token. this.addAbility(new ConditionalTriggeredAbility( - new SpellCastOpponentTriggeredAbility(new CreateTokenEffect(new EyesOfTheWisentElementalToken()), filter, true), + new SpellCastOpponentTriggeredAbility(new CreateTokenEffect(new Elemental44GreenToken()), filter, true), MyTurnCondition.instance, "Whenever an opponent casts a blue spell during your turn, you may create a 4/4 green Elemental creature token." ).addHint(MyTurnHint.instance)); diff --git a/Mage.Sets/src/mage/cards/f/FalseOrders.java b/Mage.Sets/src/mage/cards/f/FalseOrders.java index cd722afb7dc..4842979f81c 100644 --- a/Mage.Sets/src/mage/cards/f/FalseOrders.java +++ b/Mage.Sets/src/mage/cards/f/FalseOrders.java @@ -169,21 +169,6 @@ class FalseOrdersUnblockEffect extends OneShotEffect { game.fireEvent(new BlockerDeclaredEvent(chosenPermanent.getId(), permanent.getId(), permanent.getControllerId())); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKS, permanent.getId(), source, null)); } - CombatGroup blockGroup = findBlockingGroup(permanent, game); // a new blockingGroup is formed, so it's necessary to find it again - if (blockGroup != null) { - blockGroup.pickAttackerOrder(permanent.getControllerId(), game); - } return true; } - - private CombatGroup findBlockingGroup(Permanent blocker, Game game) { - if (game.getCombat().blockingGroupsContains(blocker.getId())) { // if (blocker.getBlocking() > 1) { - for (CombatGroup group : game.getCombat().getBlockingGroups()) { - if (group.getBlockers().contains(blocker.getId())) { - return group; - } - } - } - return null; - } } diff --git a/Mage.Sets/src/mage/cards/f/FireRimForm.java b/Mage.Sets/src/mage/cards/f/FireRimForm.java new file mode 100644 index 00000000000..165b1a151ef --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FireRimForm.java @@ -0,0 +1,55 @@ +package mage.cards.f; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FireRimForm extends CardImpl { + + public FireRimForm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + + this.subtype.add(SubType.AURA); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget)); + + // When this Aura enters, enchanted creature gains first strike until end of turn. + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainAbilityAttachedEffect( + FirstStrikeAbility.getInstance(), AttachmentType.AURA, Duration.EndOfTurn + ))); + + // Enchanted creature gets +2/+0. + this.addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(2, 0))); + } + + private FireRimForm(final FireRimForm card) { + super(card); + } + + @Override + public FireRimForm copy() { + return new FireRimForm(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FlashFoliage.java b/Mage.Sets/src/mage/cards/f/FlashFoliage.java index d85dcb7795c..6730fc8a77c 100644 --- a/Mage.Sets/src/mage/cards/f/FlashFoliage.java +++ b/Mage.Sets/src/mage/cards/f/FlashFoliage.java @@ -90,7 +90,6 @@ class FlashFoliageEffect extends OneShotEffect { game.getCombat().addBlockingGroup(tokenId, attackingCreature.getId(), controller.getId(), game); } } - combatGroup.pickBlockerOrder(attackingCreature.getControllerId(), game); } } return true; diff --git a/Mage.Sets/src/mage/cards/f/FleetingEffigy.java b/Mage.Sets/src/mage/cards/f/FleetingEffigy.java new file mode 100644 index 00000000000..46e227d65de --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FleetingEffigy.java @@ -0,0 +1,50 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FleetingEffigy extends CardImpl { + + public FleetingEffigy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); + + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // At the beginning of your end step, return this creature to its owner's hand. + this.addAbility(new BeginningOfEndStepTriggeredAbility(new ReturnToHandSourceEffect())); + + // {2}{R}: This creature gets +2/+0 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(2, 0, Duration.EndOfTurn), new ManaCostsImpl<>("{2}{R}") + )); + } + + private FleetingEffigy(final FleetingEffigy card) { + super(card); + } + + @Override + public FleetingEffigy copy() { + return new FleetingEffigy(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FleshCarver.java b/Mage.Sets/src/mage/cards/f/FleshCarver.java index 8247d4cbb23..7ba5d59fdcd 100644 --- a/Mage.Sets/src/mage/cards/f/FleshCarver.java +++ b/Mage.Sets/src/mage/cards/f/FleshCarver.java @@ -24,7 +24,7 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.game.permanent.token.FleshCarverHorrorToken; +import mage.game.permanent.token.HorrorXXBlackToken; import mage.players.Player; import mage.target.common.TargetControlledPermanent; @@ -110,7 +110,7 @@ class FleshCarverEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { int xValue = (Integer) getValue("power"); - return new CreateTokenEffect(new FleshCarverHorrorToken(xValue)).apply(game, source); + return new CreateTokenEffect(new HorrorXXBlackToken(xValue)).apply(game, source); } return false; } diff --git a/Mage.Sets/src/mage/cards/f/FrontlineRush.java b/Mage.Sets/src/mage/cards/f/FrontlineRush.java new file mode 100644 index 00000000000..4cab716fcb2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FrontlineRush.java @@ -0,0 +1,41 @@ +package mage.cards.f; + +import mage.abilities.Mode; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.GoblinToken; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FrontlineRush extends CardImpl { + + public FrontlineRush(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}{W}"); + + // Choose one -- + // * Create two 1/1 red Goblin creature tokens. + this.getSpellAbility().addEffect(new CreateTokenEffect(new GoblinToken(), 2)); + + // * Target creature gets +X/+X until end of turn, where X is the number of creatures you control. + this.getSpellAbility().addMode(new Mode(new BoostTargetEffect( + CreaturesYouControlCount.instance, CreaturesYouControlCount.instance + )).addTarget(new TargetCreaturePermanent())); + } + + private FrontlineRush(final FrontlineRush card) { + super(card); + } + + @Override + public FrontlineRush copy() { + return new FrontlineRush(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GeneralJarkeld.java b/Mage.Sets/src/mage/cards/g/GeneralJarkeld.java index e9eee846fe8..f05d68a0bf5 100644 --- a/Mage.Sets/src/mage/cards/g/GeneralJarkeld.java +++ b/Mage.Sets/src/mage/cards/g/GeneralJarkeld.java @@ -1,10 +1,6 @@ package mage.cards.g; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.common.IsStepCondition; @@ -13,18 +9,18 @@ import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Outcome; -import mage.constants.SuperType; -import mage.constants.PhaseStep; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.combat.CombatGroup; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetAttackingCreature; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + /** * * @author L_J @@ -138,11 +134,9 @@ class GeneralJarkeldSwitchBlockersEffect extends OneShotEffect { // the ability doesn't unblock a group that loses all blockers, however it will newly block a previously unblocked group if it gains a blocker this way if (!(chosenGroup1.getBlockers().isEmpty())) { chosenGroup1.setBlocked(true, game); - chosenGroup1.pickBlockerOrder(attacker1.getControllerId(), game); } if (!(chosenGroup2.getBlockers().isEmpty())) { chosenGroup2.setBlocked(true, game); - chosenGroup2.pickBlockerOrder(attacker2.getControllerId(), game); } return true; } @@ -197,7 +191,6 @@ class GeneralJarkeldSwitchBlockersEffect extends OneShotEffect { // 10/4/2004 The new blocker does not trigger any abilities which trigger on creatures becoming blockers, because the creatures were already blockers and the simple change of who is blocking does not trigger such abilities. game.getCombat().addBlockingGroup(blocker.getId(), attacker, controller.getId(), game); } - blockGroup.pickAttackerOrder(blocker.getControllerId(), game); } } } diff --git a/Mage.Sets/src/mage/cards/g/GlarbCalamitysAugur.java b/Mage.Sets/src/mage/cards/g/GlarbCalamitysAugur.java index 164f123c72c..516bf91b1f5 100644 --- a/Mage.Sets/src/mage/cards/g/GlarbCalamitysAugur.java +++ b/Mage.Sets/src/mage/cards/g/GlarbCalamitysAugur.java @@ -54,7 +54,7 @@ public final class GlarbCalamitysAugur extends CardImpl { this.addAbility(new SimpleStaticAbility(new PlayFromTopOfLibraryEffect(filter))); // {T}: Surveil 2. - this.addAbility(new SimpleActivatedAbility(new SurveilEffect(2), new TapSourceCost())); + this.addAbility(new SimpleActivatedAbility(new SurveilEffect(2, false), new TapSourceCost())); } private GlarbCalamitysAugur(final GlarbCalamitysAugur card) { diff --git a/Mage.Sets/src/mage/cards/g/GreatArashinCity.java b/Mage.Sets/src/mage/cards/g/GreatArashinCity.java index 9166e95fedc..ce375db023c 100644 --- a/Mage.Sets/src/mage/cards/g/GreatArashinCity.java +++ b/Mage.Sets/src/mage/cards/g/GreatArashinCity.java @@ -16,7 +16,7 @@ import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.predicate.Predicates; -import mage.game.permanent.token.SpiritWhiteToken; +import mage.game.permanent.token.NoFlyingSpiritWhiteToken; import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; @@ -47,9 +47,9 @@ public final class GreatArashinCity extends CardImpl { this.addAbility(new BlackManaAbility()); // {1}{B}, {T}, Exile a creature card from your graveyard: Create a 1/1 white Spirit creature token. - Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new SpiritWhiteToken()), new ManaCostsImpl<>("{1}{B}")); + Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new NoFlyingSpiritWhiteToken()), new ManaCostsImpl<>("{1}{B}")); ability.addCost(new TapSourceCost()); - ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE))); + ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE)).withSourceExileZone(false)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GrismoldTheDreadsower.java b/Mage.Sets/src/mage/cards/g/GrismoldTheDreadsower.java index 5ea3e290dc9..ab06afa01bb 100644 --- a/Mage.Sets/src/mage/cards/g/GrismoldTheDreadsower.java +++ b/Mage.Sets/src/mage/cards/g/GrismoldTheDreadsower.java @@ -16,7 +16,7 @@ import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TokenPredicate; -import mage.game.permanent.token.GrismoldPlantToken; +import mage.game.permanent.token.Plant11Token; import java.util.UUID; @@ -45,7 +45,7 @@ public final class GrismoldTheDreadsower extends CardImpl { // At the beginning of your end step, each player creates a 1/1 green Plant creature token. this.addAbility(new BeginningOfEndStepTriggeredAbility( - new CreateTokenAllEffect(new GrismoldPlantToken(), TargetController.EACH_PLAYER) + new CreateTokenAllEffect(new Plant11Token(), TargetController.EACH_PLAYER) )); // Whenever a creature token dies, put a +1/+1 counter on Grismold, the Dreadsower. diff --git a/Mage.Sets/src/mage/cards/g/GrovetenderDruids.java b/Mage.Sets/src/mage/cards/g/GrovetenderDruids.java index 9964ddf09b5..aedf0f54914 100644 --- a/Mage.Sets/src/mage/cards/g/GrovetenderDruids.java +++ b/Mage.Sets/src/mage/cards/g/GrovetenderDruids.java @@ -9,7 +9,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.permanent.token.GrovetenderDruidsPlantToken; +import mage.game.permanent.token.Plant11Token; import java.util.UUID; @@ -29,7 +29,7 @@ public final class GrovetenderDruids extends CardImpl { // Rally-Whenever Grovetender Druids or another Ally you control enters, you may pay {1}. // If you do, create a 1/1 green Plant creature token. this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new DoIfCostPaid( - new CreateTokenEffect(new GrovetenderDruidsPlantToken()), new GenericManaCost(1) + new CreateTokenEffect(new Plant11Token()), new GenericManaCost(1) ), false)); } diff --git a/Mage.Sets/src/mage/cards/g/GurmagRakshasa.java b/Mage.Sets/src/mage/cards/g/GurmagRakshasa.java new file mode 100644 index 00000000000..828278fe81f --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GurmagRakshasa.java @@ -0,0 +1,51 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GurmagRakshasa extends CardImpl { + + public GurmagRakshasa(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + + this.subtype.add(SubType.DEMON); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Menace + this.addAbility(new MenaceAbility()); + + // When this creature enters, target creature an opponent controls gets -2/-2 until end of turn and target creature you control gets +2/+2 until end of turn. + Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-2, -2)); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + ability.addEffect(new BoostTargetEffect(2, 2) + .setTargetPointer(new SecondTargetPointer()) + .concatBy("and")); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private GurmagRakshasa(final GurmagRakshasa card) { + super(card); + } + + @Override + public GurmagRakshasa copy() { + return new GurmagRakshasa(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HumblingElder.java b/Mage.Sets/src/mage/cards/h/HumblingElder.java new file mode 100644 index 00000000000..a79977a93c4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HumblingElder.java @@ -0,0 +1,46 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HumblingElder extends CardImpl { + + public HumblingElder(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MONK); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // When this creature enters, target creature an opponent controls gets -2/-0 until end of turn. + Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-2, 0)); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private HumblingElder(final HumblingElder card) { + super(card); + } + + @Override + public HumblingElder copy() { + return new HumblingElder(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IceridgeSerpent.java b/Mage.Sets/src/mage/cards/i/IceridgeSerpent.java new file mode 100644 index 00000000000..db31c1be839 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IceridgeSerpent.java @@ -0,0 +1,41 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IceridgeSerpent extends CardImpl { + + public IceridgeSerpent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.subtype.add(SubType.SERPENT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When this creature enters, return target creature an opponent controls to its owner's hand. + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private IceridgeSerpent(final IceridgeSerpent card) { + super(card); + } + + @Override + public IceridgeSerpent copy() { + return new IceridgeSerpent(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InfernalGenesis.java b/Mage.Sets/src/mage/cards/i/InfernalGenesis.java index 36d9fea4d6c..b2bf94bdd3c 100644 --- a/Mage.Sets/src/mage/cards/i/InfernalGenesis.java +++ b/Mage.Sets/src/mage/cards/i/InfernalGenesis.java @@ -10,7 +10,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.TargetController; import mage.game.Game; -import mage.game.permanent.token.MinionToken2; +import mage.game.permanent.token.MinionToken; import mage.game.permanent.token.Token; import mage.players.Player; @@ -42,7 +42,7 @@ public final class InfernalGenesis extends CardImpl { class InfernalGenesisEffect extends OneShotEffect { - private static final Token token = new MinionToken2(); + private static final Token token = new MinionToken(); InfernalGenesisEffect() { super(Outcome.PutCreatureInPlay); diff --git a/Mage.Sets/src/mage/cards/i/InspiritedVanguard.java b/Mage.Sets/src/mage/cards/i/InspiritedVanguard.java new file mode 100644 index 00000000000..48dc148a261 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InspiritedVanguard.java @@ -0,0 +1,38 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.effects.keyword.EndureSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InspiritedVanguard extends CardImpl { + + public InspiritedVanguard(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Whenever this creature enters or attacks, it endures 2. + this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new EndureSourceEffect(2))); + } + + private InspiritedVanguard(final InspiritedVanguard card) { + super(card); + } + + @Override + public InspiritedVanguard copy() { + return new InspiritedVanguard(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IridescentTiger.java b/Mage.Sets/src/mage/cards/i/IridescentTiger.java new file mode 100644 index 00000000000..d20ec915a85 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IridescentTiger.java @@ -0,0 +1,41 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.CastFromEverywhereSourceCondition; +import mage.abilities.effects.mana.BasicManaEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IridescentTiger extends CardImpl { + + public IridescentTiger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); + + this.subtype.add(SubType.CAT); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // When this creature enters, if you cast it, add {W}{U}{B}{R}{G}. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new BasicManaEffect(new Mana(1, 1, 1, 1, 1, 0, 0, 0)) + ).withInterveningIf(CastFromEverywhereSourceCondition.instance)); + } + + private IridescentTiger(final IridescentTiger card) { + super(card); + } + + @Override + public IridescentTiger copy() { + return new IridescentTiger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KinTreeNurturer.java b/Mage.Sets/src/mage/cards/k/KinTreeNurturer.java new file mode 100644 index 00000000000..abba7ff3cd9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KinTreeNurturer.java @@ -0,0 +1,42 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.EndureSourceEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KinTreeNurturer extends CardImpl { + + public KinTreeNurturer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // When this creature enters, it endures 1. + this.addAbility(new EntersBattlefieldTriggeredAbility(new EndureSourceEffect(1))); + } + + private KinTreeNurturer(final KinTreeNurturer card) { + super(card); + } + + @Override + public KinTreeNurturer copy() { + return new KinTreeNurturer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KnockoutManeuver.java b/Mage.Sets/src/mage/cards/k/KnockoutManeuver.java new file mode 100644 index 00000000000..528d6ddeddb --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KnockoutManeuver.java @@ -0,0 +1,37 @@ +package mage.cards.k; + +import mage.abilities.effects.common.DamageWithPowerFromOneToAnotherTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KnockoutManeuver extends CardImpl { + + public KnockoutManeuver(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); + + // Put a +1/+1 counter on target creature you control, then it deals damage equal to its power to target creature an opponent controls. + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect(", then it")); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent()); + } + + private KnockoutManeuver(final KnockoutManeuver card) { + super(card); + } + + @Override + public KnockoutManeuver copy() { + return new KnockoutManeuver(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KotisTheFangkeeper.java b/Mage.Sets/src/mage/cards/k/KotisTheFangkeeper.java new file mode 100644 index 00000000000..131dce312ea --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KotisTheFangkeeper.java @@ -0,0 +1,87 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KotisTheFangkeeper extends CardImpl { + + public KotisTheFangkeeper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{G}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Indestructible + this.addAbility(IndestructibleAbility.getInstance()); + + // Whenever Kotis deals combat damage to a player, exile the top X cards of their library, where X is the amount of damage dealt. You may cast any number of spells with mana value X or less from among them without paying their mana costs. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new KotisTheFangkeeperEffect(), false, true + )); + } + + private KotisTheFangkeeper(final KotisTheFangkeeper card) { + super(card); + } + + @Override + public KotisTheFangkeeper copy() { + return new KotisTheFangkeeper(this); + } +} + +class KotisTheFangkeeperEffect extends OneShotEffect { + + KotisTheFangkeeperEffect() { + super(Outcome.Benefit); + staticText = "exile the top X cards of their library, where X is the amount of damage dealt. You may " + + "cast any number of spells with mana value X or less from among them without paying their mana costs"; + } + + private KotisTheFangkeeperEffect(final KotisTheFangkeeperEffect effect) { + super(effect); + } + + @Override + public KotisTheFangkeeperEffect copy() { + return new KotisTheFangkeeperEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + int xValue = GetXValue.instance.calculate(game, source, this); + if (controller == null || player == null || xValue < 1) { + return false; + } + Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, xValue)); + controller.moveCards(cards, Zone.EXILED, source, game); + FilterCard filter = new FilterCard(); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, xValue + 1)); + CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, filter); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MarathWillOfTheWild.java b/Mage.Sets/src/mage/cards/m/MarathWillOfTheWild.java index c6b1fb11ff2..d8709770525 100644 --- a/Mage.Sets/src/mage/cards/m/MarathWillOfTheWild.java +++ b/Mage.Sets/src/mage/cards/m/MarathWillOfTheWild.java @@ -15,6 +15,7 @@ import mage.abilities.dynamicvalue.common.ManaSpentToCastCount; import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; @@ -27,11 +28,10 @@ import mage.constants.SuperType; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.permanent.token.MarathWillOfTheWildElementalToken; -import mage.game.permanent.token.Token; import mage.players.Player; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetCreaturePermanent; +import mage.game.permanent.token.ElementalXXGreenToken; import java.util.UUID; @@ -110,12 +110,8 @@ class MarathWillOfTheWildCreateTokenEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - int amount = GetXValue.instance.calculate(game, source, this); - Token token = new MarathWillOfTheWildElementalToken(); - token.setPower(amount); - token.setToughness(amount); - token.putOntoBattlefield(1, game, source, source.getControllerId()); - return true; + int xvalue = GetXValue.instance.calculate(game, source, this); + return new CreateTokenEffect(new ElementalXXGreenToken(xvalue)).apply(game, source); } return false; } diff --git a/Mage.Sets/src/mage/cards/m/MarshalOfTheLost.java b/Mage.Sets/src/mage/cards/m/MarshalOfTheLost.java new file mode 100644 index 00000000000..ad6fcfaf463 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MarshalOfTheLost.java @@ -0,0 +1,54 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MarshalOfTheLost extends CardImpl { + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_ATTACKING_CREATURES, null); + private static final Hint hint = new ValueHint("Attacking creatures", xValue); + + public MarshalOfTheLost(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{B}"); + + this.subtype.add(SubType.ORC); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // Whenever you attack, target creature gets +X/+X until end of turn, where X is the number of attacking creatures. + Ability ability = new AttacksWithCreaturesTriggeredAbility(new BoostTargetEffect(xValue, xValue), 1); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability.addHint(hint)); + } + + private MarshalOfTheLost(final MarshalOfTheLost card) { + super(card); + } + + @Override + public MarshalOfTheLost copy() { + return new MarshalOfTheLost(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MirrorMatch.java b/Mage.Sets/src/mage/cards/m/MirrorMatch.java index c6d0ade8f98..6efa0a8fd1e 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorMatch.java +++ b/Mage.Sets/src/mage/cards/m/MirrorMatch.java @@ -1,13 +1,12 @@ package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -20,6 +19,8 @@ import mage.players.Player; import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTargets; +import java.util.UUID; + /** * * @author LevelX2 @@ -75,20 +76,15 @@ class MirrorMatchEffect extends OneShotEffect { effect.setTargetPointer(new FixedTarget(attacker, game)); effect.apply(game, source); CombatGroup group = game.getCombat().findGroup(attacker.getId()); - boolean isCreature = false; if (group != null) { for (Permanent addedToken : effect.getAddedPermanents()) { if (addedToken.isCreature(game)) { group.addBlockerToGroup(addedToken.getId(), attackerId, game); - isCreature = true; } } ExileTargetEffect exileEffect = new ExileTargetEffect("Exile those tokens at end of combat"); exileEffect.setTargetPointer(new FixedTargets(effect.getAddedPermanents(), game)); game.addDelayedTriggeredAbility(new AtTheEndOfCombatDelayedTriggeredAbility(exileEffect), source); - if (isCreature) { - group.pickBlockerOrder(attacker.getControllerId(), game); - } } } } diff --git a/Mage.Sets/src/mage/cards/m/MoltenExhale.java b/Mage.Sets/src/mage/cards/m/MoltenExhale.java new file mode 100644 index 00000000000..b70d0407772 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MoltenExhale.java @@ -0,0 +1,40 @@ +package mage.cards.m; + +import mage.abilities.common.PayMoreToCastAsThoughtItHadFlashAbility; +import mage.abilities.costs.common.BeholdDragonCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MoltenExhale extends CardImpl { + + public MoltenExhale(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); + + // You may cast this spell as though it had flash if you behold a Dragon as an additional cost to cast it. + this.addAbility(new PayMoreToCastAsThoughtItHadFlashAbility( + this, new BeholdDragonCost(), "you may cast this spell as though " + + "it had flash if you behold a Dragon as an additional cost to cast it" + )); + + // Molten Exhale deals 4 damage to target creature or planeswalker. + this.getSpellAbility().addEffect(new DamageTargetEffect(4)); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + } + + private MoltenExhale(final MoltenExhale card) { + super(card); + } + + @Override + public MoltenExhale copy() { + return new MoltenExhale(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NightbladeBrigade.java b/Mage.Sets/src/mage/cards/n/NightbladeBrigade.java new file mode 100644 index 00000000000..2002ced44ad --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NightbladeBrigade.java @@ -0,0 +1,46 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.MobilizeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NightbladeBrigade extends CardImpl { + + public NightbladeBrigade(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // Mobilize 1 + this.addAbility(new MobilizeAbility(1)); + + // When this creature enters, surveil 1. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SurveilEffect(1))); + } + + private NightbladeBrigade(final NightbladeBrigade card) { + super(card); + } + + @Override + public NightbladeBrigade copy() { + return new NightbladeBrigade(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OverwhelmingSurge.java b/Mage.Sets/src/mage/cards/o/OverwhelmingSurge.java new file mode 100644 index 00000000000..d7734ac4db0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OverwhelmingSurge.java @@ -0,0 +1,44 @@ +package mage.cards.o; + +import mage.abilities.Mode; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OverwhelmingSurge extends CardImpl { + + public OverwhelmingSurge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); + + // Choose one or both -- + this.getSpellAbility().getModes().setMinModes(1); + this.getSpellAbility().getModes().setMaxModes(2); + + // * Overwhelming Surge deals 3 damage to target creature. + this.getSpellAbility().addEffect(new DamageTargetEffect(3)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // * Destroy target noncreature artifact. + this.getSpellAbility().addMode(new Mode(new DestroyTargetEffect()) + .addTarget(new TargetPermanent(StaticFilters.FILTER_ARTIFACT_NON_CREATURE))); + } + + private OverwhelmingSurge(final OverwhelmingSurge card) { + super(card); + } + + @Override + public OverwhelmingSurge copy() { + return new OverwhelmingSurge(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianProcessor.java b/Mage.Sets/src/mage/cards/p/PhyrexianProcessor.java index 95d06e5249f..011c55daf31 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianProcessor.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianProcessor.java @@ -8,6 +8,7 @@ import mage.abilities.costs.common.PayLifeCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -15,7 +16,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.permanent.token.MinionToken; +import mage.game.permanent.token.PhyrexianMinionToken; import mage.players.Player; import mage.util.CardUtil; @@ -110,12 +111,8 @@ class PhyrexianProcessorCreateTokenEffect extends OneShotEffect { String key = CardUtil.getCardZoneString("lifePaid", source.getSourceId(), game, true); Object object = game.getState().getValue(key); if (object instanceof Integer) { - int lifePaid = (int) object; - MinionToken token = new MinionToken(); - token.setPower(lifePaid); - token.setToughness(lifePaid); - token.putOntoBattlefield(1, game, source, source.getControllerId()); - return true; + int xvalue = (int) object; + return new CreateTokenEffect(new PhyrexianMinionToken(xvalue)).apply(game, source); } return false; } diff --git a/Mage.Sets/src/mage/cards/p/PoisedPractitioner.java b/Mage.Sets/src/mage/cards/p/PoisedPractitioner.java new file mode 100644 index 00000000000..5195c3a0a28 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PoisedPractitioner.java @@ -0,0 +1,43 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.FlurryAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PoisedPractitioner extends CardImpl { + + public PoisedPractitioner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MONK); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flurry -- Whenever you cast your second spell each turn, put a +1/+1 counter on this creature. Scry 1. + Ability ability = new FlurryAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())); + ability.addEffect(new ScryEffect(1)); + this.addAbility(ability); + } + + private PoisedPractitioner(final PoisedPractitioner card) { + super(card); + } + + @Override + public PoisedPractitioner copy() { + return new PoisedPractitioner(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RainveilRejuvenator.java b/Mage.Sets/src/mage/cards/r/RainveilRejuvenator.java new file mode 100644 index 00000000000..c878316282e --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RainveilRejuvenator.java @@ -0,0 +1,46 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerValue; +import mage.abilities.effects.common.MillCardsControllerEffect; +import mage.abilities.mana.DynamicManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RainveilRejuvenator extends CardImpl { + + public RainveilRejuvenator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.ELEPHANT); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // When this creature enters, you may mill three cards. + this.addAbility(new EntersBattlefieldTriggeredAbility(new MillCardsControllerEffect(3), true)); + + // {T}: Add an amount of {G} equal to this creature's power. + this.addAbility(new DynamicManaAbility( + Mana.GreenMana(1), SourcePermanentPowerValue.NOT_NEGATIVE, "Add an amount of {G} equal to {this}'s power." + )); + } + + private RainveilRejuvenator(final RainveilRejuvenator card) { + super(card); + } + + @Override + public RainveilRejuvenator copy() { + return new RainveilRejuvenator(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RallyTheHorde.java b/Mage.Sets/src/mage/cards/r/RallyTheHorde.java index af7546bc266..e407da6cb8c 100644 --- a/Mage.Sets/src/mage/cards/r/RallyTheHorde.java +++ b/Mage.Sets/src/mage/cards/r/RallyTheHorde.java @@ -12,7 +12,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; -import mage.game.permanent.token.RallyTheHordeWarriorToken; +import mage.game.permanent.token.RedWarriorToken; import mage.players.Player; /** @@ -72,7 +72,7 @@ class RallyTheHordeEffect extends OneShotEffect { nonLandCardsExiled += nonLands; } } - return new CreateTokenEffect(new RallyTheHordeWarriorToken(), nonLandCardsExiled).apply(game, source); + return new CreateTokenEffect(new RedWarriorToken(), nonLandCardsExiled).apply(game, source); } return false; diff --git a/Mage.Sets/src/mage/cards/r/RediscoverTheWay.java b/Mage.Sets/src/mage/cards/r/RediscoverTheWay.java new file mode 100644 index 00000000000..efab4b20360 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RediscoverTheWay.java @@ -0,0 +1,86 @@ +package mage.cards.r; + +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RediscoverTheWay extends CardImpl { + + public RediscoverTheWay(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}{R}{W}"); + + this.subtype.add(SubType.SAGA); + + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I, II -- Look at the top three cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, + new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.BOTTOM_ANY) + ); + + // III -- Whenever you cast a noncreature spell this turn, target creature you control gains double strike until end of turn. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_III, + new CreateDelayedTriggeredAbilityEffect(new RediscoverTheWayTriggeredAbility()) + ); + this.addAbility(sagaAbility); + } + + private RediscoverTheWay(final RediscoverTheWay card) { + super(card); + } + + @Override + public RediscoverTheWay copy() { + return new RediscoverTheWay(this); + } +} + +class RediscoverTheWayTriggeredAbility extends DelayedTriggeredAbility { + + RediscoverTheWayTriggeredAbility() { + super(new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance()), Duration.EndOfTurn, false, false); + this.addTarget(new TargetControlledCreaturePermanent()); + this.setTriggerPhrase("Whenever you cast a noncreature spell this turn, "); + } + + private RediscoverTheWayTriggeredAbility(final RediscoverTheWayTriggeredAbility ability) { + super(ability); + } + + @Override + public RediscoverTheWayTriggeredAbility copy() { + return new RediscoverTheWayTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!isControlledBy(event.getPlayerId())) { + return false; + } + Spell spell = game.getSpell(event.getTargetId()); + return spell != null && !spell.isCreature(game); + } +} diff --git a/Mage.Sets/src/mage/cards/r/ReputableMerchant.java b/Mage.Sets/src/mage/cards/r/ReputableMerchant.java new file mode 100644 index 00000000000..808a913f665 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/ReputableMerchant.java @@ -0,0 +1,45 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldOrDiesSourceTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ReputableMerchant extends CardImpl { + + public ReputableMerchant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2/W}{2/B}{2/G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When this creature enters or dies, put a +1/+1 counter on target creature you control. + Ability ability = new EntersBattlefieldOrDiesSourceTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false + ); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private ReputableMerchant(final ReputableMerchant card) { + super(card); + } + + @Override + public ReputableMerchant copy() { + return new ReputableMerchant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RescueLeopard.java b/Mage.Sets/src/mage/cards/r/RescueLeopard.java new file mode 100644 index 00000000000..e74c4610a5c --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RescueLeopard.java @@ -0,0 +1,41 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.BecomesTappedSourceTriggeredAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RescueLeopard extends CardImpl { + + public RescueLeopard(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.CAT); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // Whenever this creature becomes tapped, you may discard a card. If you do, draw a card. + this.addAbility(new BecomesTappedSourceTriggeredAbility( + new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new DiscardCardCost()) + )); + } + + private RescueLeopard(final RescueLeopard card) { + super(card); + } + + @Override + public RescueLeopard copy() { + return new RescueLeopard(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RevivalOfTheAncestors.java b/Mage.Sets/src/mage/cards/r/RevivalOfTheAncestors.java new file mode 100644 index 00000000000..9f73504a426 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RevivalOfTheAncestors.java @@ -0,0 +1,70 @@ +package mage.cards.r; + +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.counter.DistributeCountersEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SagaChapter; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.NoFlyingSpiritWhiteToken; +import mage.target.common.TargetCreaturePermanentAmount; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RevivalOfTheAncestors extends CardImpl { + + public RevivalOfTheAncestors(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{B}{G}"); + + this.subtype.add(SubType.SAGA); + + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I -- Create three 1/1 white Spirit creature tokens. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_I, + new CreateTokenEffect(new NoFlyingSpiritWhiteToken(), 3) + ); + + // II -- Distribute three +1/+1 counters among one, two, or three target creatures you control. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_II, + new DistributeCountersEffect(CounterType.P1P1), + new TargetCreaturePermanentAmount(3) + ); + + // III -- Creatures you control gain trample and lifelink until end of turn. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_III, + new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("creatures you control gain trample"), + new GainAbilityControlledEffect( + LifelinkAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("and lifelink until end of turn")); + this.addAbility(sagaAbility); + } + + private RevivalOfTheAncestors(final RevivalOfTheAncestors card) { + super(card); + } + + @Override + public RevivalOfTheAncestors copy() { + return new RevivalOfTheAncestors(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RiverwalkTechnique.java b/Mage.Sets/src/mage/cards/r/RiverwalkTechnique.java new file mode 100644 index 00000000000..a8547b88b2d --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RiverwalkTechnique.java @@ -0,0 +1,41 @@ +package mage.cards.r; + +import mage.abilities.Mode; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.TargetSpell; +import mage.target.common.TargetNonlandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RiverwalkTechnique extends CardImpl { + + public RiverwalkTechnique(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}"); + + // Choose one -- + // * The owner of target nonland permanent puts it on their choice of the top or bottom of their library. + this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect(true)); + this.getSpellAbility().addTarget(new TargetNonlandPermanent()); + + // * Counter target noncreature spell. + this.getSpellAbility().addMode(new Mode(new CounterTargetEffect()) + .addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_NON_CREATURE))); + } + + private RiverwalkTechnique(final RiverwalkTechnique card) { + super(card); + } + + @Override + public RiverwalkTechnique copy() { + return new RiverwalkTechnique(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SageOfTheFang.java b/Mage.Sets/src/mage/cards/s/SageOfTheFang.java new file mode 100644 index 00000000000..12a152c90d9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SageOfTheFang.java @@ -0,0 +1,51 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.RenewAbility; +import mage.abilities.effects.common.DoubleCountersTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SageOfTheFang extends CardImpl { + + public SageOfTheFang(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When this creature enters, put a +1/+1 counter on target creature. + Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + // Renew -- {3}{G}, Exile this card from your graveyard: Put a +1/+1 counter on target creature, then double the number of +1/+1 counters on that creature. + ability = new RenewAbility("{3}{G}", CounterType.P1P1.createInstance()); + ability.addEffect(new DoubleCountersTargetEffect(CounterType.P1P1) + .setText(", then double the number of +1/+1 counters on that creature")); + this.addAbility(ability); + } + + private SageOfTheFang(final SageOfTheFang card) { + super(card); + } + + @Override + public SageOfTheFang copy() { + return new SageOfTheFang(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SaguPummeler.java b/Mage.Sets/src/mage/cards/s/SaguPummeler.java new file mode 100644 index 00000000000..dcad1d18f74 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SaguPummeler.java @@ -0,0 +1,45 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.RenewAbility; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SaguPummeler extends CardImpl { + + public SaguPummeler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Renew -- {4}{G}, Exile this card from your graveyard: Put two +1/+1 counters and a reach counter on target creature. Activate only as a sorcery. + this.addAbility(new RenewAbility( + "{4}{G}", + CounterType.P1P1.createInstance(2), + CounterType.REACH.createInstance() + )); + } + + private SaguPummeler(final SaguPummeler card) { + super(card); + } + + @Override + public SaguPummeler copy() { + return new SaguPummeler(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SaltRoadSkirmish.java b/Mage.Sets/src/mage/cards/s/SaltRoadSkirmish.java new file mode 100644 index 00000000000..5f8189291b5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SaltRoadSkirmish.java @@ -0,0 +1,73 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.token.RedWarriorToken; +import mage.game.permanent.token.Token; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTargets; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SaltRoadSkirmish extends CardImpl { + + public SaltRoadSkirmish(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); + + // Destroy target creature. Create two 1/1 red Warrior creature tokens. They gain haste until end of turn. Sacrifice them at the beginning of the next end step. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addEffect(new SaltRoadSkirmishEffect()); + } + + private SaltRoadSkirmish(final SaltRoadSkirmish card) { + super(card); + } + + @Override + public SaltRoadSkirmish copy() { + return new SaltRoadSkirmish(this); + } +} + +class SaltRoadSkirmishEffect extends OneShotEffect { + + SaltRoadSkirmishEffect() { + super(Outcome.Benefit); + staticText = ""; + } + + private SaltRoadSkirmishEffect(final SaltRoadSkirmishEffect effect) { + super(effect); + } + + @Override + public SaltRoadSkirmishEffect copy() { + return new SaltRoadSkirmishEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Token token = new RedWarriorToken(); + token.putOntoBattlefield(2, game, source); + game.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance()) + .setTargetPointer(new FixedTargets(token, game)), source); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new SacrificeTargetEffect("sacrifice them").setTargetPointer(new FixedTargets(token, game)) + ), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SandskitterOutrider.java b/Mage.Sets/src/mage/cards/s/SandskitterOutrider.java new file mode 100644 index 00000000000..1904c7d10ec --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SandskitterOutrider.java @@ -0,0 +1,42 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.EndureSourceEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SandskitterOutrider extends CardImpl { + + public SandskitterOutrider(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Menace + this.addAbility(new MenaceAbility()); + + // When this creature enters, it endures 2. + this.addAbility(new EntersBattlefieldTriggeredAbility(new EndureSourceEffect(2))); + } + + private SandskitterOutrider(final SandskitterOutrider card) { + super(card); + } + + @Override + public SandskitterOutrider copy() { + return new SandskitterOutrider(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SarkhanDragonAscendant.java b/Mage.Sets/src/mage/cards/s/SarkhanDragonAscendant.java new file mode 100644 index 00000000000..555e0f6c8c3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SarkhanDragonAscendant.java @@ -0,0 +1,69 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.BeholdDragonCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.continuous.AddCardSubTypeSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SarkhanDragonAscendant extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.DRAGON, "a Dragon you control"); + + public SarkhanDragonAscendant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Sarkhan enters, you may behold a Dragon. If you do, create a Treasure token. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new DoIfCostPaid(new CreateTokenEffect(new TreasureToken()), new BeholdDragonCost()) + )); + + // Whenever a Dragon you control enters, put a +1/+1 counter on Sarkhan. Until end of turn, Sarkhan becomes a Dragon in addition to its other types and gains flying. + Ability ability = new EntersBattlefieldAllTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter + ); + ability.addEffect(new AddCardSubTypeSourceEffect( + Duration.EndOfTurn, SubType.DRAGON + ).setText("until end of turn, {this} becomes a Dragon in addition to its other types")); + ability.addEffect(new GainAbilitySourceEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains flying")); + this.addAbility(ability); + } + + private SarkhanDragonAscendant(final SarkhanDragonAscendant card) { + super(card); + } + + @Override + public SarkhanDragonAscendant copy() { + return new SarkhanDragonAscendant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SeedGuardian.java b/Mage.Sets/src/mage/cards/s/SeedGuardian.java index d1dec07dcb9..fb4935b78d2 100644 --- a/Mage.Sets/src/mage/cards/s/SeedGuardian.java +++ b/Mage.Sets/src/mage/cards/s/SeedGuardian.java @@ -14,7 +14,7 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.permanent.token.SeedGuardianToken; +import mage.game.permanent.token.ElementalXXGreenToken; import mage.players.Player; /** @@ -66,7 +66,7 @@ class SeedGuardianEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { int creaturesInGraveyard = controller.getGraveyard().count(StaticFilters.FILTER_CARD_CREATURE, game); - return new CreateTokenEffect(new SeedGuardianToken(creaturesInGraveyard)).apply(game, source); + return new CreateTokenEffect(new ElementalXXGreenToken(creaturesInGraveyard)).apply(game, source); } return false; } diff --git a/Mage.Sets/src/mage/cards/s/SibsigAppraiser.java b/Mage.Sets/src/mage/cards/s/SibsigAppraiser.java new file mode 100644 index 00000000000..43af926d85b --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SibsigAppraiser.java @@ -0,0 +1,41 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PutCards; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SibsigAppraiser extends CardImpl { + + public SibsigAppraiser(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.ADVISOR); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // When this creature enters, look at the top two cards of your library. Put one of them into your hand and the other into your graveyard. + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 2, 1, PutCards.HAND, PutCards.GRAVEYARD + ))); + } + + private SibsigAppraiser(final SibsigAppraiser card) { + super(card); + } + + @Override + public SibsigAppraiser copy() { + return new SibsigAppraiser(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SnowmeltStag.java b/Mage.Sets/src/mage/cards/s/SnowmeltStag.java new file mode 100644 index 00000000000..a72e8ad66f0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SnowmeltStag.java @@ -0,0 +1,56 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SnowmeltStag extends CardImpl { + + public SnowmeltStag(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.subtype.add(SubType.ELEMENTAL); + this.subtype.add(SubType.ELK); + this.power = new MageInt(2); + this.toughness = new MageInt(5); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // During your turn, this creature has base power and toughness 5/2. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new SetBasePowerToughnessSourceEffect(5, 2, Duration.WhileOnBattlefield), + MyTurnCondition.instance, "during your turn, this creature has base power and toughness 5/2" + ))); + + // {5}{U}{U}: This creature can't be blocked this turn. + this.addAbility(new SimpleActivatedAbility( + new CantBeBlockedSourceEffect(Duration.EndOfTurn), new ManaCostsImpl<>("{5}{U}{U}") + )); + } + + private SnowmeltStag(final SnowmeltStag card) { + super(card); + } + + @Override + public SnowmeltStag copy() { + return new SnowmeltStag(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SongcrafterMage.java b/Mage.Sets/src/mage/cards/s/SongcrafterMage.java new file mode 100644 index 00000000000..900b6a01d16 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SongcrafterMage.java @@ -0,0 +1,80 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.HarmonizeAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SongcrafterMage extends CardImpl { + + public SongcrafterMage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{U}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.BARD); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // When this creature enters, target instant or sorcery card in your graveyard gains harmonize until end of turn. Its harmonize cost is equal to its mana cost. + Ability ability = new EntersBattlefieldTriggeredAbility(new SongcrafterMageEffect()); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); + this.addAbility(ability); + } + + private SongcrafterMage(final SongcrafterMage card) { + super(card); + } + + @Override + public SongcrafterMage copy() { + return new SongcrafterMage(this); + } +} + +class SongcrafterMageEffect extends ContinuousEffectImpl { + + SongcrafterMageEffect() { + super(Duration.EndOfTurn, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + this.staticText = "target instant or sorcery card in your graveyard gains harmonize until end of turn. " + + "The harmonize cost is equal to its mana cost"; + } + + private SongcrafterMageEffect(final SongcrafterMageEffect effect) { + super(effect); + } + + @Override + public SongcrafterMageEffect copy() { + return new SongcrafterMageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + if (card == null) { + return false; + } + Ability ability = new HarmonizeAbility(card, card.getManaCost().getText()); + ability.setSourceId(card.getId()); + ability.setControllerId(card.getOwnerId()); + game.getState().addOtherAbility(card, ability); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SonicShrieker.java b/Mage.Sets/src/mage/cards/s/SonicShrieker.java new file mode 100644 index 00000000000..847e7447909 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SonicShrieker.java @@ -0,0 +1,93 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetAnyTarget; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SonicShrieker extends CardImpl { + + public SonicShrieker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{W}{B}"); + + this.subtype.add(SubType.DRAGON); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When this creature enters, it deals 2 damage to any target and you gain 2 life. If a player is dealt damage this way, they discard a card. + Ability ability = new EntersBattlefieldTriggeredAbility(new SonicShriekerEffect()); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + } + + private SonicShrieker(final SonicShrieker card) { + super(card); + } + + @Override + public SonicShrieker copy() { + return new SonicShrieker(this); + } +} + +class SonicShriekerEffect extends OneShotEffect { + + SonicShriekerEffect() { + super(Outcome.Benefit); + staticText = "it deals 2 damage to any target and you gain 2 life. " + + "If a player is dealt damage this way, they discard a card"; + } + + private SonicShriekerEffect(final SonicShriekerEffect effect) { + super(effect); + } + + @Override + public SonicShriekerEffect copy() { + return new SonicShriekerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = dealDamage(getTargetPointer().getFirst(game, source), game, source); + Optional.ofNullable(source.getControllerId()) + .map(game::getPlayer) + .ifPresent(controller -> controller.gainLife(2, game, source)); + if (player != null) { + player.discard(1, false, false, source, game); + } + return true; + } + + private static Player dealDamage(UUID targetId, Game game, Ability source) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + permanent.damage(2, source, game); + return null; + } + Player player = game.getPlayer(targetId); + if (player != null && player.damage(2, source, game) > 0) { + return player; + } + return null; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SorinSolemnVisitor.java b/Mage.Sets/src/mage/cards/s/SorinSolemnVisitor.java index ae295bea696..59e399ad294 100644 --- a/Mage.Sets/src/mage/cards/s/SorinSolemnVisitor.java +++ b/Mage.Sets/src/mage/cards/s/SorinSolemnVisitor.java @@ -17,7 +17,7 @@ import mage.constants.Duration; import mage.constants.SuperType; import mage.filter.StaticFilters; import mage.game.command.emblems.SorinSolemnVisitorEmblem; -import mage.game.permanent.token.SorinSolemnVisitorVampireToken; +import mage.game.permanent.token.VampireToken; /** * @@ -42,7 +42,7 @@ public final class SorinSolemnVisitor extends CardImpl { this.addAbility(loyaltyAbility); // -2: Create a 2/2 black Vampire creature token with flying. - this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new SorinSolemnVisitorVampireToken()), -2)); + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new VampireToken()), -2)); // -6: You get an emblem with "At the beginning of each opponent's upkeep, that player sacrifices a creature." this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new SorinSolemnVisitorEmblem()), -6)); diff --git a/Mage.Sets/src/mage/cards/s/SorrowsPath.java b/Mage.Sets/src/mage/cards/s/SorrowsPath.java index 82c220c5c8b..19836342a1f 100644 --- a/Mage.Sets/src/mage/cards/s/SorrowsPath.java +++ b/Mage.Sets/src/mage/cards/s/SorrowsPath.java @@ -176,14 +176,8 @@ class SorrowsPathSwitchBlockersEffect extends OneShotEffect { group.addBlockerToGroup(blocker.getId(), blocker.getControllerId(), game); game.getCombat().addBlockingGroup(blocker.getId(), attacker.getId(), blocker.getControllerId(), game); game.fireEvent(new BlockerDeclaredEvent(attacker.getId(), blocker.getId(), blocker.getControllerId())); - group.pickBlockerOrder(attacker.getControllerId(), game); } } game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKS, blocker.getId(), source, null)); - CombatGroup blockGroup = findBlockingGroup(blocker, game); // a new blockingGroup is formed, so it's necessary to find it again - if (blockGroup != null) { - blockGroup.pickAttackerOrder(blocker.getControllerId(), game); - } } - } diff --git a/Mage.Sets/src/mage/cards/s/SpoilsOfBlood.java b/Mage.Sets/src/mage/cards/s/SpoilsOfBlood.java index 4964fb93945..1a091662826 100644 --- a/Mage.Sets/src/mage/cards/s/SpoilsOfBlood.java +++ b/Mage.Sets/src/mage/cards/s/SpoilsOfBlood.java @@ -12,7 +12,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.game.Game; -import mage.game.permanent.token.SpoilsOfBloodHorrorToken; +import mage.game.permanent.token.HorrorXXBlackToken; import mage.players.Player; /** @@ -54,7 +54,7 @@ class SpoilsOfBloodEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { new CreateTokenEffect( - new SpoilsOfBloodHorrorToken(CreaturesDiedThisTurnCount.instance.calculate(game, source, this))) + new HorrorXXBlackToken(CreaturesDiedThisTurnCount.instance.calculate(game, source, this))) .apply(game, source); return true; } diff --git a/Mage.Sets/src/mage/cards/s/StadiumHeadliner.java b/Mage.Sets/src/mage/cards/s/StadiumHeadliner.java new file mode 100644 index 00000000000..beb0372451b --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StadiumHeadliner.java @@ -0,0 +1,52 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerValue; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.MobilizeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StadiumHeadliner extends CardImpl { + + public StadiumHeadliner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Mobilize 1 + this.addAbility(new MobilizeAbility(1)); + + // {1}{R}, Sacrifice this creature: It deals damage equal to the number of creatures you control to target creature. + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect( + SourcePermanentPowerValue.NOT_NEGATIVE, "it" + ), new ManaCostsImpl<>("{1}{R}")); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private StadiumHeadliner(final StadiumHeadliner card) { + super(card); + } + + @Override + public StadiumHeadliner copy() { + return new StadiumHeadliner(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StaticSnare.java b/Mage.Sets/src/mage/cards/s/StaticSnare.java new file mode 100644 index 00000000000..532e26e12b3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StaticSnare.java @@ -0,0 +1,55 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; +import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StaticSnare extends CardImpl { + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_ATTACKING_CREATURE); + private static final Hint hint = new ValueHint("Attacking creatures", xValue); + + public StaticSnare(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{W}"); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // This spell costs {1} less to cast for each attacking creature. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SpellCostReductionForEachSourceEffect(1, xValue) + ).addHint(hint)); + + // When this enchantment enters, exile target artifact or creature an opponent controls until this enchantment leaves the battlefield. + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileUntilSourceLeavesEffect()); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_ARTIFACT_OR_CREATURE)); + this.addAbility(ability); + } + + private StaticSnare(final StaticSnare card) { + super(card); + } + + @Override + public StaticSnare copy() { + return new StaticSnare(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StormbeaconBlade.java b/Mage.Sets/src/mage/cards/s/StormbeaconBlade.java new file mode 100644 index 00000000000..2b6d9fba1c2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StormbeaconBlade.java @@ -0,0 +1,57 @@ +package mage.cards.s; + +import mage.abilities.common.AttacksAttachedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StormbeaconBlade extends CardImpl { + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + StaticFilters.FILTER_ATTACKING_CREATURE, + ComparisonType.MORE_THAN, 2, true + ); + + public StormbeaconBlade(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{W}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Equipped creature gets +3/+0. + this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(3, 0))); + + // Whenever equipped creature attacks, draw a card if you control three or more attacking creatures. + this.addAbility(new AttacksAttachedTriggeredAbility(new ConditionalOneShotEffect( + new DrawCardSourceControllerEffect(1), condition, + "draw a card if you control three or more attacking creatures" + ), AttachmentType.EQUIPMENT, false)); + + // Equip {2} + this.addAbility(new EquipAbility(2)); + } + + private StormbeaconBlade(final StormbeaconBlade card) { + super(card); + } + + @Override + public StormbeaconBlade copy() { + return new StormbeaconBlade(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TeemingDragonstorm.java b/Mage.Sets/src/mage/cards/t/TeemingDragonstorm.java new file mode 100644 index 00000000000..0683450554e --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TeemingDragonstorm.java @@ -0,0 +1,41 @@ +package mage.cards.t; + +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.game.permanent.token.Soldier22Token; + +import java.util.UUID; + +/** + * @author PurpleCrowbar + */ +public final class TeemingDragonstorm extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.DRAGON, "a Dragon"); + + public TeemingDragonstorm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); + + // When this enchantment enters, create two 2/2 white Soldier creature tokens. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new Soldier22Token(), 2), false)); + + // When a Dragon you control enters, return this enchantment to its owner's hand. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new ReturnToHandSourceEffect(), filter)); + } + + private TeemingDragonstorm (final TeemingDragonstorm card) { + super(card); + } + + @Override + public TeemingDragonstorm copy() { + return new TeemingDragonstorm(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TevalsJudgment.java b/Mage.Sets/src/mage/cards/t/TevalsJudgment.java new file mode 100644 index 00000000000..3f50b543be4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TevalsJudgment.java @@ -0,0 +1,47 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.CardsLeaveGraveyardTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.TreasureToken; +import mage.game.permanent.token.ZombieDruidToken; + +import java.util.UUID; + +/** + * @author PurpleCrowbar + */ +public final class TevalsJudgment extends CardImpl { + + public TevalsJudgment(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); + + // Whenever one or more cards leave your graveyard, choose one that hasn’t been chosen this turn -- + // * Draw a card. + Ability ability = new CardsLeaveGraveyardTriggeredAbility( + new DrawCardSourceControllerEffect(1) + ); + ability.getModes().setLimitUsageByOnce(true); + + // * Create a Treasure token. + ability.addMode(new Mode(new CreateTokenEffect(new TreasureToken()))); + + // * Create a 2/2 black Zombie Druid creature token. + ability.addMode(new Mode(new CreateTokenEffect(new ZombieDruidToken()))); + this.addAbility(ability); + } + + private TevalsJudgment(final TevalsJudgment card) { + super(card); + } + + @Override + public TevalsJudgment copy() { + return new TevalsJudgment(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheSecondDoctor.java b/Mage.Sets/src/mage/cards/t/TheSecondDoctor.java new file mode 100644 index 00000000000..3553ed8bf51 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheSecondDoctor.java @@ -0,0 +1,141 @@ +package mage.cards.t; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.RestrictionEffect; +import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author padfoothelix + */ +public final class TheSecondDoctor extends CardImpl { + + public TheSecondDoctor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.TIME_LORD); + this.subtype.add(SubType.DOCTOR); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Players have no maximum hand size. + this.addAbility(new SimpleStaticAbility(new MaximumHandSizeControllerEffect( + Integer.MAX_VALUE, Duration.WhileOnBattlefield, + MaximumHandSizeControllerEffect.HandSizeModification.SET, TargetController.ANY + ))); + + // How Civil of You -- At the beginning of your end step, each player may draw a card. Each opponent who does can't attack you or permanents you control during their next turn. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new TheSecondDoctorEffect()).withFlavorWord("How Civil of You")); + } + + private TheSecondDoctor(final TheSecondDoctor card) { + super(card); + } + + @Override + public TheSecondDoctor copy() { + return new TheSecondDoctor(this); + } +} + +class TheSecondDoctorEffect extends OneShotEffect { + TheSecondDoctorEffect() { + super(Outcome.Benefit); + this.staticText = "each player may draw a card. Each opponent who does can't attack you or permanents you control during their next turn."; + } + + private TheSecondDoctorEffect(final TheSecondDoctorEffect effect) { + super(effect); + } + + @Override + public TheSecondDoctorEffect copy() { + return new TheSecondDoctorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null + && player.chooseUse(Outcome.DrawCard, "Draw a card ?", source, game) + && player.drawCards(1, source, game) > 0 + && game.getOpponents(controller.getId()).contains(playerId)) { + RestrictionEffect effect = new TheSecondDoctorCantAttackEffect(player.getId()); + game.addEffect(effect, source); + } + } + return true; + } +} + +class TheSecondDoctorCantAttackEffect extends RestrictionEffect { + + private final UUID opponentId; + + public TheSecondDoctorCantAttackEffect(UUID opponentId) { + super(Duration.UntilEndOfYourNextTurn); + this.opponentId = opponentId; + staticText = ""; + } + + private TheSecondDoctorCantAttackEffect(final TheSecondDoctorCantAttackEffect effect) { + super(effect); + this.opponentId = effect.opponentId; + } + + @Override + public TheSecondDoctorCantAttackEffect copy() { + return new TheSecondDoctorCantAttackEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + if (opponentId != null) { + setStartingControllerAndTurnNum(game, opponentId, game.getActivePlayerId()); + } else { + discard(); + } + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return game.isActivePlayer(opponentId); + } + + @Override + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + UUID controllerId = source.getControllerId(); + // defender is null + if (defenderId == null) { + return true; + } + // defender is a permanent + Permanent defender = game.getPermanent(defenderId); + if (defender != null) { + return !defender.isControlledBy(controllerId); + } + // defender is a player + return !defenderId.equals(controllerId); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheSibsigCeremony.java b/Mage.Sets/src/mage/cards/t/TheSibsigCeremony.java new file mode 100644 index 00000000000..cf5c66c47fc --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheSibsigCeremony.java @@ -0,0 +1,77 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.Predicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.ZombieDruidToken; +import mage.game.stack.Spell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheSibsigCeremony extends CardImpl { + + private static final FilterCard filter = new FilterCreatureCard("creature spells"); + private static final FilterPermanent filter2 = new FilterControlledCreaturePermanent(); + + static { + filter2.add(TheSibsigCeremonyPredicate.instance); + } + + public TheSibsigCeremony(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}{B}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + + // Creature spells you cast cost {2} less to cast. + this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 2))); + + // Whenever a creature you control enters, if you cast it, destroy that creature, then create a 2/2 black Zombie Druid creature token. + Ability ability = new EntersBattlefieldAllTriggeredAbility( + Zone.BATTLEFIELD, new DestroyTargetEffect() + .setText("if you cast it, destroy that creature"), + filter2, false, SetTargetPointer.PERMANENT + ); + ability.addEffect(new CreateTokenEffect(new ZombieDruidToken()).concatBy(", then")); + this.addAbility(ability); + } + + private TheSibsigCeremony(final TheSibsigCeremony card) { + super(card); + } + + @Override + public TheSibsigCeremony copy() { + return new TheSibsigCeremony(this); + } +} + +enum TheSibsigCeremonyPredicate implements Predicate { + instance; + + @Override + public boolean apply(Permanent input, Game game) { + int zcc = input.getZoneChangeCounter(game); + Spell spell = game.getStack().getSpell(input.getId()); + return (spell != null && spell.getZoneChangeCounter(game) == zcc - 1) + || game.getLastKnownInformation(input.getId(), Zone.STACK, zcc - 1) != null; + } +} diff --git a/Mage.Sets/src/mage/cards/t/ThisIsHowItEnds.java b/Mage.Sets/src/mage/cards/t/ThisIsHowItEnds.java new file mode 100644 index 00000000000..15b6ed745aa --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThisIsHowItEnds.java @@ -0,0 +1,108 @@ +package mage.cards.t; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ShuffleIntoLibraryTargetEffect; +import mage.cards.*; +import mage.choices.FaceVillainousChoice; +import mage.choices.VillainousChoice; +import mage.constants.*; +import mage.game.Game; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author padfoothelix + */ +public final class ThisIsHowItEnds extends CardImpl { + + public ThisIsHowItEnds(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}"); + + // Target creature's owner shuffles it into their library, then faces a villainous choice -- They lose 5 life, or they shuffle another creature they own into their library. + this.getSpellAbility().addEffect( + new ShuffleIntoLibraryTargetEffect() + .setText("target creature's owner shuffles it into their library,") + ); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addEffect(new ThisIsHowItEndsEffect()); + + } + + private ThisIsHowItEnds(final ThisIsHowItEnds card) { + super(card); + } + + @Override + public ThisIsHowItEnds copy() { + return new ThisIsHowItEnds(this); + } +} + +class ThisIsHowItEndsEffect extends OneShotEffect { + + private static final FaceVillainousChoice choice = new FaceVillainousChoice( + Outcome.Removal, new ThisIsHowItEndsFirstChoice(), new ThisIsHowItEndsSecondChoice() + ); + + ThisIsHowItEndsEffect() { + super(Outcome.Benefit); + staticText = "then " + choice.generateRule(); + } + + private ThisIsHowItEndsEffect(final ThisIsHowItEndsEffect effect) { + super(effect); + } + + @Override + public ThisIsHowItEndsEffect copy() { + return new ThisIsHowItEndsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + UUID targetOwnerId = game.getOwnerId(getTargetPointer().getFirst(game, source)); + Player targetOwner = game.getPlayer(targetOwnerId); + choice.faceChoice(targetOwner, game, source); + return true; + } +} + +class ThisIsHowItEndsFirstChoice extends VillainousChoice { + ThisIsHowItEndsFirstChoice() { + super("They lose 5 life","You lose 5 life"); + } + + @Override + public boolean doChoice(Player player, Game game, Ability source) { + player.loseLife(5, game, source, false); + return true; + } +} + +class ThisIsHowItEndsSecondChoice extends VillainousChoice { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you own"); + + static { + filter.add(TargetController.YOU.getOwnerPredicate()); + } + + ThisIsHowItEndsSecondChoice() { + super("they shuffle another creature they own into their library", "you shuffle a creature you own into your library"); + } + + @Override + public boolean doChoice(Player player, Game game, Ability source) { + TargetCreaturePermanent target = new TargetCreaturePermanent(1, 1, filter, true); + target.withChooseHint("to shuffle into your library"); + player.chooseTarget(Outcome.Detriment, target, source, game); + Cards cards = new CardsImpl(target.getTargets()); + player.shuffleCardsToLibrary(cards, game, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/ThunderOfUnity.java b/Mage.Sets/src/mage/cards/t/ThunderOfUnity.java new file mode 100644 index 00000000000..e1619ec66d4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThunderOfUnity.java @@ -0,0 +1,83 @@ +package mage.cards.t; + +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.common.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SagaChapter; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ThunderOfUnity extends CardImpl { + + public ThunderOfUnity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}{W}{B}"); + + this.subtype.add(SubType.SAGA); + + // (As this Saga enters step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I -- You draw two cards and you lose 2 life. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_I, + new DrawCardSourceControllerEffect(2, true), + new LoseLifeSourceControllerEffect(2).concatBy("and") + ); + + // II, III -- Whenever a creature you control enters this turn, each opponent loses 1 life and you gain 1 life. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_III, + new CreateDelayedTriggeredAbilityEffect(new ThunderOfUnityTriggeredAbility()) + ); + this.addAbility(sagaAbility); + } + + private ThunderOfUnity(final ThunderOfUnity card) { + super(card); + } + + @Override + public ThunderOfUnity copy() { + return new ThunderOfUnity(this); + } +} + +class ThunderOfUnityTriggeredAbility extends DelayedTriggeredAbility { + + ThunderOfUnityTriggeredAbility() { + super(new LoseLifeOpponentsEffect(1), Duration.EndOfTurn, false, false); + this.addEffect(new GainLifeEffect(1).concatBy("and")); + this.setTriggerPhrase("Whenever a creature you control enters this turn, "); + } + + private ThunderOfUnityTriggeredAbility(final ThunderOfUnityTriggeredAbility ability) { + super(ability); + } + + @Override + public ThunderOfUnityTriggeredAbility copy() { + return new ThunderOfUnityTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent permanent = game.getPermanent(event.getTargetId()); + return permanent != null && permanent.isCreature(game) && permanent.isControlledBy(getControllerId()); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TradeRouteEnvoy.java b/Mage.Sets/src/mage/cards/t/TradeRouteEnvoy.java new file mode 100644 index 00000000000..28512ab25a8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TradeRouteEnvoy.java @@ -0,0 +1,84 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.CounterAnyPredicate; +import mage.game.Game; +import mage.players.Player; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TradeRouteEnvoy extends CardImpl { + + public TradeRouteEnvoy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.DOG); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // When this creature enters, draw a card if you control a creature with a counter on it. If you don't draw a card this way, put a +1/+1 counter on this creature. + this.addAbility(new EntersBattlefieldTriggeredAbility(new TradeRouteEnvoyEffect())); + } + + private TradeRouteEnvoy(final TradeRouteEnvoy card) { + super(card); + } + + @Override + public TradeRouteEnvoy copy() { + return new TradeRouteEnvoy(this); + } +} + +class TradeRouteEnvoyEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(CounterAnyPredicate.instance); + } + + TradeRouteEnvoyEffect() { + super(Outcome.Benefit); + staticText = "draw a card if you control a creature with a counter on it. " + + "If you don't draw a card this way, put a +1/+1 counter on this creature"; + } + + private TradeRouteEnvoyEffect(final TradeRouteEnvoyEffect effect) { + super(effect); + } + + @Override + public TradeRouteEnvoyEffect copy() { + return new TradeRouteEnvoyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (game.getBattlefield().contains(filter, source, game, 1)) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null && player.drawCards(1, source, game) > 0) { + return true; + } + } + Optional.ofNullable(source.getSourcePermanentIfItStillExists(game)) + .ifPresent(permanent -> permanent.addCounters(CounterType.P1P1.createInstance(), source, game)); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TravelingBotanist.java b/Mage.Sets/src/mage/cards/t/TravelingBotanist.java new file mode 100644 index 00000000000..31fac690a1c --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TravelingBotanist.java @@ -0,0 +1,88 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BecomesTappedSourceTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TravelingBotanist extends CardImpl { + + public TravelingBotanist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.DOG); + this.subtype.add(SubType.SCOUT); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Whenever this creature becomes tapped, look at the top card of your library. If it's a land card, you may reveal it and put it into your hand. If you don't put the card into your hand, you may put it into your graveyard. + this.addAbility(new BecomesTappedSourceTriggeredAbility(new TravelingBotanistEffect())); + } + + private TravelingBotanist(final TravelingBotanist card) { + super(card); + } + + @Override + public TravelingBotanist copy() { + return new TravelingBotanist(this); + } +} + +class TravelingBotanistEffect extends OneShotEffect { + + TravelingBotanistEffect() { + super(Outcome.Benefit); + staticText = "look at the top card of your library. If it's a land card, you may reveal it and " + + "put it into your hand. If you don't put the card into your hand, you may put it into your graveyard"; + } + + private TravelingBotanistEffect(final TravelingBotanistEffect effect) { + super(effect); + } + + @Override + public TravelingBotanistEffect copy() { + return new TravelingBotanistEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Card card = player.getLibrary().getFromTop(game); + if (card == null) { + return false; + } + player.lookAtCards("Top card of library", card, game); + if (card.isLand(game) && player.chooseUse( + Outcome.DrawCard, "Reveal " + card.getName() + + " and put it into your hand?", source, game + )) { + player.revealCards(source, new CardsImpl(card), game); + player.moveCards(card, Zone.HAND, source, game); + return true; + } + if (player.chooseUse(Outcome.Neutral, "Put " + card.getName() + " into your graveyard?", source, game)) { + return player.moveCards(card, Zone.GRAVEYARD, source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TumbleweedRising.java b/Mage.Sets/src/mage/cards/t/TumbleweedRising.java index a553fc1d14b..fa0239749b6 100644 --- a/Mage.Sets/src/mage/cards/t/TumbleweedRising.java +++ b/Mage.Sets/src/mage/cards/t/TumbleweedRising.java @@ -10,7 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.game.Game; -import mage.game.permanent.token.SeedGuardianToken; +import mage.game.permanent.token.ElementalXXGreenToken; import java.util.UUID; @@ -61,6 +61,6 @@ class TumbleweedRisingEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int xvalue = GreatestPowerAmongControlledCreaturesValue.instance.calculate(game, source, this); - return new CreateTokenEffect(new SeedGuardianToken(xvalue)).apply(game, source); + return new CreateTokenEffect(new ElementalXXGreenToken(xvalue)).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/u/UnburiedEarthcarver.java b/Mage.Sets/src/mage/cards/u/UnburiedEarthcarver.java new file mode 100644 index 00000000000..96d624833d2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnburiedEarthcarver.java @@ -0,0 +1,47 @@ +package mage.cards.u; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnburiedEarthcarver extends CardImpl { + + public UnburiedEarthcarver(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {2}, Sacrifice another creature: Put a +1/+1 counter on this creature. + Ability ability = new SimpleActivatedAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new GenericManaCost(2) + ); + ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_ANOTHER_CREATURE)); + this.addAbility(ability); + } + + private UnburiedEarthcarver(final UnburiedEarthcarver card) { + super(card); + } + + @Override + public UnburiedEarthcarver copy() { + return new UnburiedEarthcarver(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VeiledApparition.java b/Mage.Sets/src/mage/cards/v/VeiledApparition.java index 6d23247eca8..ddb202c6119 100644 --- a/Mage.Sets/src/mage/cards/v/VeiledApparition.java +++ b/Mage.Sets/src/mage/cards/v/VeiledApparition.java @@ -1,17 +1,15 @@ package mage.cards.v; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SpellCastOpponentTriggeredAbility; import mage.abilities.condition.common.SourceMatchesFilterCondition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.common.DoUnlessControllerPaysEffect; -import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -21,6 +19,8 @@ import mage.filter.FilterSpell; import mage.filter.StaticFilters; import mage.game.permanent.token.TokenImpl; +import java.util.UUID; + /** * * @author jeffwadsworth @@ -33,7 +33,7 @@ public final class VeiledApparition extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); // When an opponent casts a spell, if Veiled Apparition is an enchantment, Veiled Apparition becomes a 3/3 Illusion creature with flying and "At the beginning of your upkeep, sacrifice Veiled Apparition unless you pay {1}{U}." - TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new VeilApparitionToken(), null, Duration.WhileOnBattlefield), + TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new VeiledApparitionToken(), null, Duration.WhileOnBattlefield), filter, false); this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), "When an opponent casts a spell, if {this} is an enchantment, {this} becomes a 3/3 Illusion creature with flying and \"At the beginning of your upkeep, sacrifice Veiled Apparition unless you pay {1}{U}.\"")); @@ -50,23 +50,25 @@ public final class VeiledApparition extends CardImpl { } } -class VeilApparitionToken extends TokenImpl { +class VeiledApparitionToken extends TokenImpl { - public VeilApparitionToken() { + VeiledApparitionToken() { super("Illusion", "3/3 Illusion creature with flying and \"At the beginning of your upkeep, sacrifice Veiled Apparition unless you pay {1}{U}."); cardType.add(CardType.CREATURE); subtype.add(SubType.ILLUSION); power = new MageInt(3); toughness = new MageInt(3); - Ability ability = new BeginningOfUpkeepTriggeredAbility(new DoUnlessControllerPaysEffect(new SacrificeSourceEffect(), new ManaCostsImpl<>("{1}{U}"))); - this.addAbility(ability); + this.addAbility(FlyingAbility.getInstance()); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl<>("{1}{U}")) + )); } - private VeilApparitionToken(final VeilApparitionToken token) { + private VeiledApparitionToken(final VeiledApparitionToken token) { super(token); } - public VeilApparitionToken copy() { - return new VeilApparitionToken(this); + public VeiledApparitionToken copy() { + return new VeiledApparitionToken(this); } } diff --git a/Mage.Sets/src/mage/cards/v/VeteranIceClimber.java b/Mage.Sets/src/mage/cards/v/VeteranIceClimber.java new file mode 100644 index 00000000000..e4057da3457 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VeteranIceClimber.java @@ -0,0 +1,51 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerValue; +import mage.abilities.effects.common.MillCardsTargetEffect; +import mage.abilities.keyword.CantBeBlockedSourceAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.TargetPlayer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VeteranIceClimber extends CardImpl { + + public VeteranIceClimber(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SCOUT); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // This creature can't be blocked. + this.addAbility(new CantBeBlockedSourceAbility()); + + // Whenever this creature attacks, up to one target player mills cards equal to this creature's power. + Ability ability = new AttacksTriggeredAbility(new MillCardsTargetEffect(SourcePermanentPowerValue.NOT_NEGATIVE)); + ability.addTarget(new TargetPlayer(0, 1, false)); + this.addAbility(ability); + } + + private VeteranIceClimber(final VeteranIceClimber card) { + super(card); + } + + @Override + public VeteranIceClimber copy() { + return new VeteranIceClimber(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WalkerOfTheGrove.java b/Mage.Sets/src/mage/cards/w/WalkerOfTheGrove.java index 98f5d3eba23..22005807dbf 100644 --- a/Mage.Sets/src/mage/cards/w/WalkerOfTheGrove.java +++ b/Mage.Sets/src/mage/cards/w/WalkerOfTheGrove.java @@ -10,7 +10,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.permanent.token.WalkerOfTheGroveToken; +import mage.game.permanent.token.Elemental44GreenToken; /** * @@ -26,7 +26,7 @@ public final class WalkerOfTheGrove extends CardImpl { this.toughness = new MageInt(7); // When Walker of the Grove leaves the battlefield, create a 4/4 green Elemental creature token. - this.addAbility(new LeavesBattlefieldTriggeredAbility(new CreateTokenEffect(new WalkerOfTheGroveToken(), 1), false)); + this.addAbility(new LeavesBattlefieldTriggeredAbility(new CreateTokenEffect(new Elemental44GreenToken(), 1), false)); // Evoke {4}{G} this.addAbility(new EvokeAbility("{4}{G}")); } diff --git a/Mage.Sets/src/mage/cards/w/WarEffort.java b/Mage.Sets/src/mage/cards/w/WarEffort.java new file mode 100644 index 00000000000..3c5b7ee0af5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WarEffort.java @@ -0,0 +1,73 @@ +package mage.cards.w; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.token.RedWarriorToken; +import mage.game.permanent.token.Token; +import mage.target.targetpointer.FixedTargets; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WarEffort extends CardImpl { + + public WarEffort(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); + + // Creatures you control get +1/+0. + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(1, 0, Duration.WhileOnBattlefield))); + + // Whenever you attack, create a 1/1 red Warrior creature token that's tapped and attacking. Sacrifice it at the beginning of the next end step. + this.addAbility(new AttacksWithCreaturesTriggeredAbility(new WarEffortEffect(), 1)); + } + + private WarEffort(final WarEffort card) { + super(card); + } + + @Override + public WarEffort copy() { + return new WarEffort(this); + } +} + +class WarEffortEffect extends OneShotEffect { + + WarEffortEffect() { + super(Outcome.Benefit); + staticText = "create a 1/1 red Warrior creature token that's tapped and attacking. " + + "Sacrifice it at the beginning of the next end step"; + } + + private WarEffortEffect(final WarEffortEffect effect) { + super(effect); + } + + @Override + public WarEffortEffect copy() { + return new WarEffortEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Token token = new RedWarriorToken(); + token.putOntoBattlefield(1, game, source, source.getControllerId(), true, true); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new SacrificeTargetEffect("sacrifice it").setTargetPointer(new FixedTargets(token, game)) + ), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/w/WayspeakerBodyguard.java b/Mage.Sets/src/mage/cards/w/WayspeakerBodyguard.java new file mode 100644 index 00000000000..b7f5291cddf --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WayspeakerBodyguard.java @@ -0,0 +1,62 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.FlurryAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.common.FilterNonlandCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.filter.predicate.mageobject.PermanentPredicate; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WayspeakerBodyguard extends CardImpl { + + private static final FilterCard filter = new FilterNonlandCard("nonland permanent card with mana value 2 or less"); + + static { + filter.add(PermanentPredicate.instance); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 3)); + } + + public WayspeakerBodyguard(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.ORC); + this.subtype.add(SubType.MONK); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // When this creature enters, return target nonland permanent card with mana value 2 or less from your graveyard to your hand. + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); + + // Flurry -- Whenever you cast your second spell each turn, tap target creature an opponent controls. + ability = new FlurryAbility(new TapTargetEffect()); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private WayspeakerBodyguard(final WayspeakerBodyguard card) { + super(card); + } + + @Override + public WayspeakerBodyguard copy() { + return new WayspeakerBodyguard(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WildRide.java b/Mage.Sets/src/mage/cards/w/WildRide.java new file mode 100644 index 00000000000..c049cc6f6a2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WildRide.java @@ -0,0 +1,44 @@ +package mage.cards.w; + +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HarmonizeAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WildRide extends CardImpl { + + public WildRide(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{R}"); + + // Target creature gets +3/+0 and gains haste until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect( + 3, 0, Duration.EndOfTurn + ).setText("Target creature gets +3/+0")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains haste until end of turn")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Harmonize {4}{R} + this.addAbility(new HarmonizeAbility(this, "{4}{R}")); + } + + private WildRide(final WildRide card) { + super(card); + } + + @Override + public WildRide copy() { + return new WildRide(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WingbladeDisciple.java b/Mage.Sets/src/mage/cards/w/WingbladeDisciple.java new file mode 100644 index 00000000000..e1c925d30e7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WingbladeDisciple.java @@ -0,0 +1,43 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.FlurryAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.BirdToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WingbladeDisciple extends CardImpl { + + public WingbladeDisciple(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MONK); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Flurry -- Whenever you cast your second spell each turn, create a 1/1 white Bird creature token with flying. + this.addAbility(new FlurryAbility(new CreateTokenEffect(new BirdToken()))); + } + + private WingbladeDisciple(final WingbladeDisciple card) { + super(card); + } + + @Override + public WingbladeDisciple copy() { + return new WingbladeDisciple(this); + } +} diff --git a/Mage.Sets/src/mage/cards/y/YathanRoadwatcher.java b/Mage.Sets/src/mage/cards/y/YathanRoadwatcher.java new file mode 100644 index 00000000000..c48e3de7af9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/y/YathanRoadwatcher.java @@ -0,0 +1,60 @@ +package mage.cards.y; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.condition.common.CastFromEverywhereSourceCondition; +import mage.abilities.costs.common.MillCardsCost; +import mage.abilities.effects.common.DoWhenCostPaid; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class YathanRoadwatcher extends CardImpl { + + private static final FilterCard filter + = new FilterCreatureCard("creature card with mana value 3 or less from your graveyard"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); + } + + public YathanRoadwatcher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{B}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SCOUT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When this creature enters, if you cast it, mill four cards. When you do, return target creature card with mana value 3 or less from your graveyard to the battlefield. + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect(), false + ); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DoWhenCostPaid( + ability, new MillCardsCost(4), "", false + )).withInterveningIf(CastFromEverywhereSourceCondition.instance)); + } + + private YathanRoadwatcher(final YathanRoadwatcher card) { + super(card); + } + + @Override + public YathanRoadwatcher copy() { + return new YathanRoadwatcher(this); + } +} diff --git a/Mage.Sets/src/mage/cards/z/ZurgoThundersDecree.java b/Mage.Sets/src/mage/cards/z/ZurgoThundersDecree.java new file mode 100644 index 00000000000..be9b2e959ff --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZurgoThundersDecree.java @@ -0,0 +1,58 @@ +package mage.cards.z; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.IsStepCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.CantBeSacrificedSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.MobilizeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.predicate.permanent.TokenPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ZurgoThundersDecree extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.WARRIOR, ""); + + static { + filter.add(TokenPredicate.TRUE); + } + + private static final Condition condition = new IsStepCondition(PhaseStep.END_TURN, true); + + public ZurgoThundersDecree(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{W}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.ORC); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Mobilize 2 + this.addAbility(new MobilizeAbility(2)); + + // During your end step, Warrior tokens you control have "This token can't be sacrificed." + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(new GainAbilityControlledEffect( + new SimpleStaticAbility(new CantBeSacrificedSourceEffect()), Duration.WhileOnBattlefield + ), condition, "during your end step, Warrior tokens you control have \"This token can't be sacrificed.\""))); + } + + private ZurgoThundersDecree(final ZurgoThundersDecree card) { + super(card); + } + + @Override + public ZurgoThundersDecree copy() { + return new ZurgoThundersDecree(this); + } +} diff --git a/Mage.Sets/src/mage/sets/AetherdriftCommander.java b/Mage.Sets/src/mage/sets/AetherdriftCommander.java index 5707ceedfc3..5cb696fed4c 100644 --- a/Mage.Sets/src/mage/sets/AetherdriftCommander.java +++ b/Mage.Sets/src/mage/sets/AetherdriftCommander.java @@ -118,7 +118,7 @@ public final class AetherdriftCommander extends ExpansionSet { cards.add(new SetCardInfo("Maskwood Nexus", 132, Rarity.RARE, mage.cards.m.MaskwoodNexus.class)); cards.add(new SetCardInfo("Midnight Clock", 79, Rarity.RARE, mage.cards.m.MidnightClock.class)); cards.add(new SetCardInfo("Midnight Reaper", 44, Rarity.RARE, mage.cards.m.MidnightReaper.class)); - cards.add(new SetCardInfo("Murderous Rider // Swift End", 45, Rarity.RARE, mage.cards.m.MurderousRider.class)); + cards.add(new SetCardInfo("Murderous Rider", 45, Rarity.RARE, mage.cards.m.MurderousRider.class)); cards.add(new SetCardInfo("Never // Return", 96, Rarity.RARE, mage.cards.n.NeverReturn.class)); cards.add(new SetCardInfo("Nissa, Worldsoul Speaker", 13, Rarity.RARE, mage.cards.n.NissaWorldsoulSpeaker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nissa, Worldsoul Speaker", 29, Rarity.RARE, mage.cards.n.NissaWorldsoulSpeaker.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/DoctorWho.java b/Mage.Sets/src/mage/sets/DoctorWho.java index b70357f6180..e03ac42718d 100644 --- a/Mage.Sets/src/mage/sets/DoctorWho.java +++ b/Mage.Sets/src/mage/sets/DoctorWho.java @@ -1010,13 +1010,13 @@ public final class DoctorWho extends ExpansionSet { cards.add(new SetCardInfo("The Rani", 754, Rarity.RARE, mage.cards.t.TheRani.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Sea Devils", 108, Rarity.RARE, mage.cards.t.TheSeaDevils.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Sea Devils", 713, Rarity.RARE, mage.cards.t.TheSeaDevils.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("The Second Doctor", "553z", Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("The Second Doctor", 1031, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("The Second Doctor", 1144, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("The Second Doctor", 156, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("The Second Doctor", 440, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("The Second Doctor", 553, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("The Second Doctor", 761, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Second Doctor", "553z", Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Second Doctor", 1031, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Second Doctor", 1144, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Second Doctor", 156, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Second Doctor", 440, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Second Doctor", 553, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Second Doctor", 761, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); //cards.add(new SetCardInfo("The Seventh Doctor", "558z", Rarity.RARE, mage.cards.t.TheSeventhDoctor.class, NON_FULL_USE_VARIOUS)); //cards.add(new SetCardInfo("The Seventh Doctor", 1033, Rarity.RARE, mage.cards.t.TheSeventhDoctor.class, NON_FULL_USE_VARIOUS)); //cards.add(new SetCardInfo("The Seventh Doctor", 1149, Rarity.RARE, mage.cards.t.TheSeventhDoctor.class, NON_FULL_USE_VARIOUS)); @@ -1093,10 +1093,10 @@ public final class DoctorWho extends ExpansionSet { cards.add(new SetCardInfo("Thijarian Witness", 716, Rarity.UNCOMMON, mage.cards.t.ThijarianWitness.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Think Twice", 220, Rarity.COMMON, mage.cards.t.ThinkTwice.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Think Twice", 811, Rarity.COMMON, mage.cards.t.ThinkTwice.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("This Is How It Ends", 373, Rarity.RARE, mage.cards.t.ThisIsHowItEnds.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("This Is How It Ends", 675, Rarity.RARE, mage.cards.t.ThisIsHowItEnds.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("This Is How It Ends", 70, Rarity.RARE, mage.cards.t.ThisIsHowItEnds.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("This Is How It Ends", 964, Rarity.RARE, mage.cards.t.ThisIsHowItEnds.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("This Is How It Ends", 373, Rarity.RARE, mage.cards.t.ThisIsHowItEnds.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("This Is How It Ends", 675, Rarity.RARE, mage.cards.t.ThisIsHowItEnds.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("This Is How It Ends", 70, Rarity.RARE, mage.cards.t.ThisIsHowItEnds.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("This Is How It Ends", 964, Rarity.RARE, mage.cards.t.ThisIsHowItEnds.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thought Vessel", 255, Rarity.UNCOMMON, mage.cards.t.ThoughtVessel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thought Vessel", 846, Rarity.UNCOMMON, mage.cards.t.ThoughtVessel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Three Visits", 235, Rarity.UNCOMMON, mage.cards.t.ThreeVisits.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/MediaAndCollaborationPromos.java b/Mage.Sets/src/mage/sets/MediaAndCollaborationPromos.java index 1454b11516d..e867776dd97 100644 --- a/Mage.Sets/src/mage/sets/MediaAndCollaborationPromos.java +++ b/Mage.Sets/src/mage/sets/MediaAndCollaborationPromos.java @@ -22,37 +22,69 @@ public class MediaAndCollaborationPromos extends ExpansionSet { // some cards are non-English (most are Japanese, Jamuraan Lion has a German printing), but it's ok - scryfall can download it - cards.add(new SetCardInfo("Archangel", 29, Rarity.RARE, mage.cards.a.Archangel.class)); - cards.add(new SetCardInfo("Ascendant Evincar", 28, Rarity.RARE, mage.cards.a.AscendantEvincar.class)); - cards.add(new SetCardInfo("Blue Elemental Blast", 5, Rarity.COMMON, mage.cards.b.BlueElementalBlast.class)); - cards.add(new SetCardInfo("Cast Down", 30, Rarity.UNCOMMON, mage.cards.c.CastDown.class)); - cards.add(new SetCardInfo("Chandra's Outrage", 18, Rarity.COMMON, mage.cards.c.ChandrasOutrage.class)); - cards.add(new SetCardInfo("Chandra's Spitfire", 19, Rarity.UNCOMMON, mage.cards.c.ChandrasSpitfire.class)); - cards.add(new SetCardInfo("Cunning Sparkmage", 17, Rarity.UNCOMMON, mage.cards.c.CunningSparkmage.class)); - cards.add(new SetCardInfo("Darksteel Juggernaut", 16, Rarity.RARE, mage.cards.d.DarksteelJuggernaut.class)); - cards.add(new SetCardInfo("Daxos, Blessed by the Sun", 36, Rarity.UNCOMMON, mage.cards.d.DaxosBlessedByTheSun.class)); - cards.add(new SetCardInfo("Diabolic Edict", 31, Rarity.RARE, mage.cards.d.DiabolicEdict.class)); - cards.add(new SetCardInfo("Duress", 34, Rarity.RARE, mage.cards.d.Duress.class)); - cards.add(new SetCardInfo("Fireball", 4, Rarity.COMMON, mage.cards.f.Fireball.class)); - cards.add(new SetCardInfo("Jamuraan Lion", "10*", Rarity.COMMON, mage.cards.j.JamuraanLion.class)); - cards.add(new SetCardInfo("Kuldotha Phoenix", 20, Rarity.RARE, mage.cards.k.KuldothaPhoenix.class)); - cards.add(new SetCardInfo("Lava Coil", 33, Rarity.UNCOMMON, mage.cards.l.LavaCoil.class)); - cards.add(new SetCardInfo("Lightning Hounds", 10, Rarity.COMMON, mage.cards.l.LightningHounds.class)); - cards.add(new SetCardInfo("Parallax Dementia", 27, Rarity.COMMON, mage.cards.p.ParallaxDementia.class)); - cards.add(new SetCardInfo("Phantasmal Dragon", 21, Rarity.UNCOMMON, mage.cards.p.PhantasmalDragon.class)); - cards.add(new SetCardInfo("Phyrexian Rager", 14, Rarity.COMMON, mage.cards.p.PhyrexianRager.class)); - cards.add(new SetCardInfo("Sandbar Crocodile", 22, Rarity.COMMON, mage.cards.s.SandbarCrocodile.class)); - cards.add(new SetCardInfo("Scent of Cinder", 9, Rarity.COMMON, mage.cards.s.ScentOfCinder.class)); - cards.add(new SetCardInfo("Shivan Dragon", 15, Rarity.RARE, mage.cards.s.ShivanDragon.class)); - cards.add(new SetCardInfo("Shock", 32, Rarity.RARE, mage.cards.s.Shock.class)); - cards.add(new SetCardInfo("Shrieking Drake", 24, Rarity.COMMON, mage.cards.s.ShriekingDrake.class)); - cards.add(new SetCardInfo("Silver Drake", 13, Rarity.COMMON, mage.cards.s.SilverDrake.class)); - cards.add(new SetCardInfo("Spined Wurm", 11, Rarity.COMMON, mage.cards.s.SpinedWurm.class)); - cards.add(new SetCardInfo("Staggering Insight", 37, Rarity.RARE, mage.cards.s.StaggeringInsight.class)); - cards.add(new SetCardInfo("Stream of Life", 25, Rarity.COMMON, mage.cards.s.StreamOfLife.class)); - cards.add(new SetCardInfo("Thorn Elemental", 26, Rarity.RARE, mage.cards.t.ThornElemental.class)); - cards.add(new SetCardInfo("Voltaic Key", 35, Rarity.RARE, mage.cards.v.VoltaicKey.class)); - cards.add(new SetCardInfo("Warmonger", 12, Rarity.UNCOMMON, mage.cards.w.Warmonger.class)); - cards.add(new SetCardInfo("Zhalfirin Knight", 23, Rarity.COMMON, mage.cards.z.ZhalfirinKnight.class)); + cards.add(new SetCardInfo("Ajani, Mentor of Heroes", "2024-3", Rarity.MYTHIC, mage.cards.a.AjaniMentorOfHeroes.class)); + cards.add(new SetCardInfo("Ancestral Mask", "2025-2", Rarity.RARE, mage.cards.a.AncestralMask.class)); + cards.add(new SetCardInfo("Archangel", "2000-4", Rarity.RARE, mage.cards.a.Archangel.class)); + cards.add(new SetCardInfo("Ascendant Evincar", "2000-7", Rarity.RARE, mage.cards.a.AscendantEvincar.class)); + cards.add(new SetCardInfo("Avalanche Riders", "2023-5", Rarity.RARE, mage.cards.a.AvalancheRiders.class)); + cards.add(new SetCardInfo("Blue Elemental Blast", "1995-2", Rarity.COMMON, mage.cards.b.BlueElementalBlast.class)); + cards.add(new SetCardInfo("Bone Shredder", "2021-2", Rarity.RARE, mage.cards.b.BoneShredder.class)); + cards.add(new SetCardInfo("Cast Down", "2019-1", Rarity.UNCOMMON, mage.cards.c.CastDown.class)); + cards.add(new SetCardInfo("Chandra's Outrage", "2010-3", Rarity.COMMON, mage.cards.c.ChandrasOutrage.class)); + cards.add(new SetCardInfo("Chandra's Spitfire", "2010-4", Rarity.UNCOMMON, mage.cards.c.ChandrasSpitfire.class)); + cards.add(new SetCardInfo("Counterspell", "2021-1", Rarity.RARE, mage.cards.c.Counterspell.class)); + cards.add(new SetCardInfo("Crop Rotation", "2020-7ww", Rarity.RARE, mage.cards.c.CropRotation.class)); + cards.add(new SetCardInfo("Culling the Weak", "2023-8", Rarity.RARE, mage.cards.c.CullingTheWeak.class)); + cards.add(new SetCardInfo("Cunning Sparkmage", "2010-2", Rarity.UNCOMMON, mage.cards.c.CunningSparkmage.class)); + cards.add(new SetCardInfo("Dark Ritual", "2020-4", Rarity.RARE, mage.cards.d.DarkRitual.class)); + cards.add(new SetCardInfo("Darksteel Juggernaut", "2010-1", Rarity.RARE, mage.cards.d.DarksteelJuggernaut.class)); + cards.add(new SetCardInfo("Daxos, Blessed by the Sun", "2020-2", Rarity.UNCOMMON, mage.cards.d.DaxosBlessedByTheSun.class)); + cards.add(new SetCardInfo("Diabolic Edict", "2024-5", Rarity.RARE, mage.cards.d.DiabolicEdict.class)); + cards.add(new SetCardInfo("Disenchant", "2022-1", Rarity.RARE, mage.cards.d.Disenchant.class)); + cards.add(new SetCardInfo("Duress", "2025-7", Rarity.RARE, mage.cards.d.Duress.class)); + cards.add(new SetCardInfo("Fireball", "1995-1", Rarity.COMMON, mage.cards.f.Fireball.class)); + cards.add(new SetCardInfo("Frantic Search", "2022-4", Rarity.RARE, mage.cards.f.FranticSearch.class)); + cards.add(new SetCardInfo("Gingerbrute", "2023-3", Rarity.RARE, mage.cards.g.Gingerbrute.class)); + cards.add(new SetCardInfo("Gush", "2024-4", Rarity.RARE, mage.cards.g.Gush.class)); + cards.add(new SetCardInfo("Harald, King of Skemfar", "2021-3", Rarity.RARE, mage.cards.h.HaraldKingOfSkemfar.class)); + cards.add(new SetCardInfo("Heliod's Pilgrim", "2020-6", Rarity.RARE, mage.cards.h.HeliodsPilgrim.class)); + cards.add(new SetCardInfo("Hypnotic Sprite", "2019-5", Rarity.RARE, mage.cards.h.HypnoticSprite.class)); + cards.add(new SetCardInfo("Jace Beleren", "2009-1", Rarity.MYTHIC, mage.cards.j.JaceBeleren.class)); + cards.add(new SetCardInfo("Jace, Memory Adept", "2024-2", Rarity.MYTHIC, mage.cards.j.JaceMemoryAdept.class)); + cards.add(new SetCardInfo("Jamuraan Lion", "1996-3", Rarity.COMMON, mage.cards.j.JamuraanLion.class)); + cards.add(new SetCardInfo("Kuldotha Phoenix", "2010-5", Rarity.RARE, mage.cards.k.KuldothaPhoenix.class)); + cards.add(new SetCardInfo("Lava Coil", "2019-4", Rarity.UNCOMMON, mage.cards.l.LavaCoil.class)); + cards.add(new SetCardInfo("Lightning Hounds", "2000-1", Rarity.COMMON, mage.cards.l.LightningHounds.class)); + cards.add(new SetCardInfo("Liliana of the Dark Realms", "2024-8", Rarity.MYTHIC, mage.cards.l.LilianaOfTheDarkRealms.class)); + cards.add(new SetCardInfo("Mental Misstep", "2023-1", Rarity.RARE, mage.cards.m.MentalMisstep.class)); + cards.add(new SetCardInfo("Nicol Bolas, Planeswalker", "2025-10", Rarity.MYTHIC, mage.cards.n.NicolBolasPlaneswalker.class)); + cards.add(new SetCardInfo("Parallax Dementia", "2000-6", Rarity.COMMON, mage.cards.p.ParallaxDementia.class)); + cards.add(new SetCardInfo("Patchwork Banner", "2024-7", Rarity.RARE, mage.cards.p.PatchworkBanner.class)); + cards.add(new SetCardInfo("Phantasmal Dragon", "2011-1", Rarity.UNCOMMON, mage.cards.p.PhantasmalDragon.class)); + cards.add(new SetCardInfo("Phyrexian Rager", "2000-5", Rarity.COMMON, mage.cards.p.PhyrexianRager.class)); + cards.add(new SetCardInfo("Pyromancer's Gauntlet", "2023-6", Rarity.RARE, mage.cards.p.PyromancersGauntlet.class)); + cards.add(new SetCardInfo("Ruin Crab", "2023-4", Rarity.RARE, mage.cards.r.RuinCrab.class)); + cards.add(new SetCardInfo("Sandbar Crocodile", "1996-1", Rarity.COMMON, mage.cards.s.SandbarCrocodile.class)); + cards.add(new SetCardInfo("Scent of Cinder", "1999-1", Rarity.COMMON, mage.cards.s.ScentOfCinder.class)); + cards.add(new SetCardInfo("Shield Wall", "1997-3", Rarity.COMMON, mage.cards.s.ShieldWall.class)); + cards.add(new SetCardInfo("Shivan Dragon", "2001-2", Rarity.RARE, mage.cards.s.ShivanDragon.class)); + cards.add(new SetCardInfo("Shock", "2025-1", Rarity.RARE, mage.cards.s.Shock.class)); + cards.add(new SetCardInfo("Shrieking Drake", "1997-2", Rarity.COMMON, mage.cards.s.ShriekingDrake.class)); + cards.add(new SetCardInfo("Silver Drake", "2000-2", Rarity.COMMON, mage.cards.s.SilverDrake.class)); + cards.add(new SetCardInfo("Snuff Out", "2024-1", Rarity.RARE, mage.cards.s.SnuffOut.class)); + cards.add(new SetCardInfo("Spined Wurm", "2001-1", Rarity.COMMON, mage.cards.s.SpinedWurm.class)); + cards.add(new SetCardInfo("Sprite Dragon", "2020-5", Rarity.RARE, mage.cards.s.SpriteDragon.class)); + cards.add(new SetCardInfo("Staggering Insight", "2020-3", Rarity.RARE, mage.cards.s.StaggeringInsight.class)); + cards.add(new SetCardInfo("Stream of Life", "1997-4", Rarity.COMMON, mage.cards.s.StreamOfLife.class)); + cards.add(new SetCardInfo("Talruum Champion", "1997-1", Rarity.COMMON, mage.cards.t.TalruumChampion.class)); + cards.add(new SetCardInfo("Tangled Florahedron", "2020-8", Rarity.UNCOMMON, mage.cards.t.TangledFlorahedron.class)); + cards.add(new SetCardInfo("Thorn Elemental", "2000-3", Rarity.RARE, mage.cards.t.ThornElemental.class)); + cards.add(new SetCardInfo("Usher of the Fallen", "2022-3", Rarity.RARE, mage.cards.u.UsherOfTheFallen.class)); + cards.add(new SetCardInfo("Voltaic Key", "2024-6", Rarity.RARE, mage.cards.v.VoltaicKey.class)); + cards.add(new SetCardInfo("Warmonger", "1999-2", Rarity.UNCOMMON, mage.cards.w.Warmonger.class)); + cards.add(new SetCardInfo("Wild Growth", "2022-2", Rarity.RARE, mage.cards.w.WildGrowth.class)); + cards.add(new SetCardInfo("Winged Boots", "2023-7", Rarity.RARE, mage.cards.w.WingedBoots.class)); + cards.add(new SetCardInfo("Worn Powerstone", "2023-2", Rarity.RARE, mage.cards.w.WornPowerstone.class)); + cards.add(new SetCardInfo("Zhalfirin Knight", "1996-2", Rarity.COMMON, mage.cards.z.ZhalfirinKnight.class)); } } diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 0afdfafe8bc..1a0c64cf5d8 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -12,7 +12,7 @@ import java.util.List; */ public final class TarkirDragonstorm extends ExpansionSet { - private static final List unfinished = Arrays.asList("Channeled Dragonfire", "Glacial Dragonhunt", "Mammoth Bellow", "Nature's Rhythm", "Roamer's Routine", "Songcrafter Mage", "Synchronized Charge", "Unending Whisper", "Ureni's Rebuff", "Winternight Stories"); + private static final List unfinished = Arrays.asList("Channeled Dragonfire", "Glacial Dragonhunt", "Mammoth Bellow", "Nature's Rhythm", "Roamer's Routine", "Songcrafter Mage", "Synchronized Charge", "Unending Whisper", "Ureni's Rebuff", "Wild Ride", "Winternight Stories"); private static final TarkirDragonstorm instance = new TarkirDragonstorm(); public static TarkirDragonstorm getInstance() { @@ -26,11 +26,15 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Abzan Devotee", 68, Rarity.COMMON, mage.cards.a.AbzanDevotee.class)); cards.add(new SetCardInfo("Abzan Monument", 238, Rarity.UNCOMMON, mage.cards.a.AbzanMonument.class)); + cards.add(new SetCardInfo("Adorned Crocodile", 69, Rarity.COMMON, mage.cards.a.AdornedCrocodile.class)); cards.add(new SetCardInfo("Aegis Sculptor", 35, Rarity.UNCOMMON, mage.cards.a.AegisSculptor.class)); cards.add(new SetCardInfo("Agent of Kotis", 36, Rarity.COMMON, mage.cards.a.AgentOfKotis.class)); + cards.add(new SetCardInfo("Ainok Wayfarer", 134, Rarity.COMMON, mage.cards.a.AinokWayfarer.class)); + cards.add(new SetCardInfo("Alchemist's Assistant", 71, Rarity.UNCOMMON, mage.cards.a.AlchemistsAssistant.class)); cards.add(new SetCardInfo("Alesha's Legacy", 72, Rarity.COMMON, mage.cards.a.AleshasLegacy.class)); cards.add(new SetCardInfo("Ambling Stormshell", 37, Rarity.RARE, mage.cards.a.AmblingStormshell.class)); cards.add(new SetCardInfo("Anafenza, Unyielding Lineage", 2, Rarity.RARE, mage.cards.a.AnafenzaUnyieldingLineage.class)); + cards.add(new SetCardInfo("Arashin Sunshield", 3, Rarity.COMMON, mage.cards.a.ArashinSunshield.class)); cards.add(new SetCardInfo("Armament Dragon", 168, Rarity.UNCOMMON, mage.cards.a.ArmamentDragon.class)); cards.add(new SetCardInfo("Attuned Hunter", 135, Rarity.UNCOMMON, mage.cards.a.AttunedHunter.class)); cards.add(new SetCardInfo("Auroral Procession", 169, Rarity.UNCOMMON, mage.cards.a.AuroralProcession.class)); @@ -46,7 +50,9 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Breaching Dragonstorm", 101, Rarity.UNCOMMON, mage.cards.b.BreachingDragonstorm.class)); cards.add(new SetCardInfo("Call the Spirit Dragons", 174, Rarity.MYTHIC, mage.cards.c.CallTheSpiritDragons.class)); cards.add(new SetCardInfo("Caustic Exhale", 74, Rarity.COMMON, mage.cards.c.CausticExhale.class)); + cards.add(new SetCardInfo("Champion of Dusan", 137, Rarity.COMMON, mage.cards.c.ChampionOfDusan.class)); cards.add(new SetCardInfo("Channeled Dragonfire", 102, Rarity.UNCOMMON, mage.cards.c.ChanneledDragonfire.class)); + cards.add(new SetCardInfo("Constrictor Sage", 39, Rarity.UNCOMMON, mage.cards.c.ConstrictorSage.class)); cards.add(new SetCardInfo("Coordinated Maneuver", 6, Rarity.COMMON, mage.cards.c.CoordinatedManeuver.class)); cards.add(new SetCardInfo("Cori Mountain Monastery", 252, Rarity.RARE, mage.cards.c.CoriMountainMonastery.class)); cards.add(new SetCardInfo("Cori Mountain Stalwart", 175, Rarity.UNCOMMON, mage.cards.c.CoriMountainStalwart.class)); @@ -62,6 +68,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Dismal Backwater", 254, Rarity.COMMON, mage.cards.d.DismalBackwater.class)); cards.add(new SetCardInfo("Dispelling Exhale", 41, Rarity.COMMON, mage.cards.d.DispellingExhale.class)); cards.add(new SetCardInfo("Dracogenesis", 105, Rarity.MYTHIC, mage.cards.d.Dracogenesis.class)); + cards.add(new SetCardInfo("Dragon Sniper", 139, Rarity.UNCOMMON, mage.cards.d.DragonSniper.class)); cards.add(new SetCardInfo("Dragon's Prey", 79, Rarity.COMMON, mage.cards.d.DragonsPrey.class)); cards.add(new SetCardInfo("Dragonback Assault", 179, Rarity.MYTHIC, mage.cards.d.DragonbackAssault.class)); cards.add(new SetCardInfo("Dragonback Lancer", 9, Rarity.COMMON, mage.cards.d.DragonbackLancer.class)); @@ -71,22 +78,32 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Dragonstorm Globe", 241, Rarity.COMMON, mage.cards.d.DragonstormGlobe.class)); cards.add(new SetCardInfo("Dusyut Earthcarver", 141, Rarity.COMMON, mage.cards.d.DusyutEarthcarver.class)); cards.add(new SetCardInfo("Duty Beyond Death", 10, Rarity.UNCOMMON, mage.cards.d.DutyBeyondDeath.class)); + cards.add(new SetCardInfo("Elspeth, Storm Slayer", 11, Rarity.MYTHIC, mage.cards.e.ElspethStormSlayer.class)); cards.add(new SetCardInfo("Embermouth Sentinel", 242, Rarity.COMMON, mage.cards.e.EmbermouthSentinel.class)); cards.add(new SetCardInfo("Encroaching Dragonstorm", 142, Rarity.UNCOMMON, mage.cards.e.EncroachingDragonstorm.class)); cards.add(new SetCardInfo("Equilibrium Adept", 106, Rarity.UNCOMMON, mage.cards.e.EquilibriumAdept.class)); + cards.add(new SetCardInfo("Essence Anchor", 44, Rarity.UNCOMMON, mage.cards.e.EssenceAnchor.class)); cards.add(new SetCardInfo("Evolving Wilds", 255, Rarity.COMMON, mage.cards.e.EvolvingWilds.class)); cards.add(new SetCardInfo("Fangkeeper's Familiar", 183, Rarity.RARE, mage.cards.f.FangkeepersFamiliar.class)); cards.add(new SetCardInfo("Felothar, Dawn of the Abzan", 184, Rarity.RARE, mage.cards.f.FelotharDawnOfTheAbzan.class)); + cards.add(new SetCardInfo("Fire-Rim Form", 107, Rarity.COMMON, mage.cards.f.FireRimForm.class)); + cards.add(new SetCardInfo("Fleeting Effigy", 108, Rarity.UNCOMMON, mage.cards.f.FleetingEffigy.class)); cards.add(new SetCardInfo("Forest", 285, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fortress Kin-Guard", 12, Rarity.COMMON, mage.cards.f.FortressKinGuard.class)); cards.add(new SetCardInfo("Fresh Start", 46, Rarity.UNCOMMON, mage.cards.f.FreshStart.class)); cards.add(new SetCardInfo("Frontier Bivouac", 256, Rarity.UNCOMMON, mage.cards.f.FrontierBivouac.class)); + cards.add(new SetCardInfo("Frontline Rush", 186, Rarity.UNCOMMON, mage.cards.f.FrontlineRush.class)); cards.add(new SetCardInfo("Glacial Dragonhunt", 188, Rarity.UNCOMMON, mage.cards.g.GlacialDragonhunt.class)); cards.add(new SetCardInfo("Great Arashin City", 257, Rarity.RARE, mage.cards.g.GreatArashinCity.class)); cards.add(new SetCardInfo("Gurmag Nightwatch", 190, Rarity.COMMON, mage.cards.g.GurmagNightwatch.class)); + cards.add(new SetCardInfo("Gurmag Rakshasa", 81, Rarity.UNCOMMON, mage.cards.g.GurmagRakshasa.class)); cards.add(new SetCardInfo("Hardened Tactician", 191, Rarity.UNCOMMON, mage.cards.h.HardenedTactician.class)); cards.add(new SetCardInfo("Heritage Reclamation", 145, Rarity.COMMON, mage.cards.h.HeritageReclamation.class)); + cards.add(new SetCardInfo("Humbling Elder", 48, Rarity.COMMON, mage.cards.h.HumblingElder.class)); + cards.add(new SetCardInfo("Iceridge Serpent", 49, Rarity.COMMON, mage.cards.i.IceridgeSerpent.class)); cards.add(new SetCardInfo("Inevitable Defeat", 194, Rarity.RARE, mage.cards.i.InevitableDefeat.class)); + cards.add(new SetCardInfo("Inspirited Vanguard", 146, Rarity.UNCOMMON, mage.cards.i.InspiritedVanguard.class)); + cards.add(new SetCardInfo("Iridescent Tiger", 109, Rarity.UNCOMMON, mage.cards.i.IridescentTiger.class)); cards.add(new SetCardInfo("Island", 279, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Jade-Cast Sentinel", 243, Rarity.COMMON, mage.cards.j.JadeCastSentinel.class)); cards.add(new SetCardInfo("Jeskai Brushmaster", 195, Rarity.UNCOMMON, mage.cards.j.JeskaiBrushmaster.class)); @@ -95,17 +112,22 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Jeskai Shrinekeeper", 197, Rarity.UNCOMMON, mage.cards.j.JeskaiShrinekeeper.class)); cards.add(new SetCardInfo("Jungle Hollow", 258, Rarity.COMMON, mage.cards.j.JungleHollow.class)); cards.add(new SetCardInfo("Kheru Goldkeeper", 199, Rarity.UNCOMMON, mage.cards.k.KheruGoldkeeper.class)); + cards.add(new SetCardInfo("Kin-Tree Nurturer", 83, Rarity.COMMON, mage.cards.k.KinTreeNurturer.class)); cards.add(new SetCardInfo("Kin-Tree Severance", 200, Rarity.UNCOMMON, mage.cards.k.KinTreeSeverance.class)); cards.add(new SetCardInfo("Kishla Skimmer", 201, Rarity.UNCOMMON, mage.cards.k.KishlaSkimmer.class)); cards.add(new SetCardInfo("Kishla Trawlers", 50, Rarity.UNCOMMON, mage.cards.k.KishlaTrawlers.class)); cards.add(new SetCardInfo("Kishla Village", 259, Rarity.RARE, mage.cards.k.KishlaVillage.class)); + cards.add(new SetCardInfo("Knockout Maneuver", 147, Rarity.UNCOMMON, mage.cards.k.KnockoutManeuver.class)); + cards.add(new SetCardInfo("Kotis, the Fangkeeper", 202, Rarity.RARE, mage.cards.k.KotisTheFangkeeper.class)); cards.add(new SetCardInfo("Krotiq Nestguard", 148, Rarity.COMMON, mage.cards.k.KrotiqNestguard.class)); cards.add(new SetCardInfo("Lightfoot Technique", 14, Rarity.COMMON, mage.cards.l.LightfootTechnique.class)); cards.add(new SetCardInfo("Loxodon Battle Priest", 15, Rarity.UNCOMMON, mage.cards.l.LoxodonBattlePriest.class)); cards.add(new SetCardInfo("Mammoth Bellow", 205, Rarity.UNCOMMON, mage.cards.m.MammothBellow.class)); cards.add(new SetCardInfo("Mardu Devotee", 16, Rarity.COMMON, mage.cards.m.MarduDevotee.class)); cards.add(new SetCardInfo("Mardu Monument", 245, Rarity.UNCOMMON, mage.cards.m.MarduMonument.class)); + cards.add(new SetCardInfo("Marshal of the Lost", 207, Rarity.UNCOMMON, mage.cards.m.MarshalOfTheLost.class)); cards.add(new SetCardInfo("Meticulous Artisan", 112, Rarity.COMMON, mage.cards.m.MeticulousArtisan.class)); + cards.add(new SetCardInfo("Molten Exhale", 113, Rarity.COMMON, mage.cards.m.MoltenExhale.class)); cards.add(new SetCardInfo("Monastery Messenger", 208, Rarity.COMMON, mage.cards.m.MonasteryMessenger.class)); cards.add(new SetCardInfo("Mountain", 283, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mox Jasper", 246, Rarity.MYTHIC, mage.cards.m.MoxJasper.class)); @@ -114,34 +136,55 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Narset, Jeskai Waymaster", 209, Rarity.RARE, mage.cards.n.NarsetJeskaiWaymaster.class)); cards.add(new SetCardInfo("Nature's Rhythm", 150, Rarity.RARE, mage.cards.n.NaturesRhythm.class)); cards.add(new SetCardInfo("Neriv, Heart of the Storm", 210, Rarity.MYTHIC, mage.cards.n.NerivHeartOfTheStorm.class)); + cards.add(new SetCardInfo("Nightblade Brigade", 85, Rarity.COMMON, mage.cards.n.NightbladeBrigade.class)); cards.add(new SetCardInfo("Nomad Outpost", 263, Rarity.UNCOMMON, mage.cards.n.NomadOutpost.class)); cards.add(new SetCardInfo("Opulent Palace", 264, Rarity.UNCOMMON, mage.cards.o.OpulentPalace.class)); cards.add(new SetCardInfo("Osseous Exhale", 17, Rarity.COMMON, mage.cards.o.OsseousExhale.class)); + cards.add(new SetCardInfo("Overwhelming Surge", 115, Rarity.UNCOMMON, mage.cards.o.OverwhelmingSurge.class)); cards.add(new SetCardInfo("Piercing Exhale", 151, Rarity.COMMON, mage.cards.p.PiercingExhale.class)); cards.add(new SetCardInfo("Plains", 277, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Poised Practitioner", 18, Rarity.COMMON, mage.cards.p.PoisedPractitioner.class)); cards.add(new SetCardInfo("Qarsi Revenant", 86, Rarity.RARE, mage.cards.q.QarsiRevenant.class)); + cards.add(new SetCardInfo("Rainveil Rejuvenator", 152, Rarity.UNCOMMON, mage.cards.r.RainveilRejuvenator.class)); cards.add(new SetCardInfo("Rakshasa's Bargain", 214, Rarity.UNCOMMON, mage.cards.r.RakshasasBargain.class)); cards.add(new SetCardInfo("Rally the Monastery", 19, Rarity.UNCOMMON, mage.cards.r.RallyTheMonastery.class)); cards.add(new SetCardInfo("Rebellious Strike", 20, Rarity.COMMON, mage.cards.r.RebelliousStrike.class)); + cards.add(new SetCardInfo("Rediscover the Way", 215, Rarity.RARE, mage.cards.r.RediscoverTheWay.class)); cards.add(new SetCardInfo("Reigning Victor", 216, Rarity.COMMON, mage.cards.r.ReigningVictor.class)); + cards.add(new SetCardInfo("Reputable Merchant", 217, Rarity.COMMON, mage.cards.r.ReputableMerchant.class)); + cards.add(new SetCardInfo("Rescue Leopard", 116, Rarity.COMMON, mage.cards.r.RescueLeopard.class)); + cards.add(new SetCardInfo("Revival of the Ancestors", 218, Rarity.RARE, mage.cards.r.RevivalOfTheAncestors.class)); cards.add(new SetCardInfo("Ringing Strike Mastery", 53, Rarity.COMMON, mage.cards.r.RingingStrikeMastery.class)); + cards.add(new SetCardInfo("Riverwalk Technique", 54, Rarity.COMMON, mage.cards.r.RiverwalkTechnique.class)); cards.add(new SetCardInfo("Roamer's Routine", 154, Rarity.COMMON, mage.cards.r.RoamersRoutine.class)); cards.add(new SetCardInfo("Roar of Endless Song", 220, Rarity.RARE, mage.cards.r.RoarOfEndlessSong.class)); cards.add(new SetCardInfo("Roiling Dragonstorm", 55, Rarity.UNCOMMON, mage.cards.r.RoilingDragonstorm.class)); cards.add(new SetCardInfo("Rugged Highlands", 265, Rarity.COMMON, mage.cards.r.RuggedHighlands.class)); + cards.add(new SetCardInfo("Sage of the Fang", 155, Rarity.UNCOMMON, mage.cards.s.SageOfTheFang.class)); + cards.add(new SetCardInfo("Sagu Pummeler", 156, Rarity.COMMON, mage.cards.s.SaguPummeler.class)); cards.add(new SetCardInfo("Salt Road Packbeast", 23, Rarity.COMMON, mage.cards.s.SaltRoadPackbeast.class)); + cards.add(new SetCardInfo("Salt Road Skirmish", 88, Rarity.UNCOMMON, mage.cards.s.SaltRoadSkirmish.class)); + cards.add(new SetCardInfo("Sandskitter Outrider", 89, Rarity.COMMON, mage.cards.s.SandskitterOutrider.class)); cards.add(new SetCardInfo("Sandsteppe Citadel", 266, Rarity.UNCOMMON, mage.cards.s.SandsteppeCitadel.class)); cards.add(new SetCardInfo("Sarkhan's Resolve", 158, Rarity.COMMON, mage.cards.s.SarkhansResolve.class)); + cards.add(new SetCardInfo("Sarkhan, Dragon Ascendant", 118, Rarity.RARE, mage.cards.s.SarkhanDragonAscendant.class)); cards.add(new SetCardInfo("Scoured Barrens", 267, Rarity.COMMON, mage.cards.s.ScouredBarrens.class)); cards.add(new SetCardInfo("Seize Opportunity", 119, Rarity.COMMON, mage.cards.s.SeizeOpportunity.class)); cards.add(new SetCardInfo("Shiko, Paragon of the Way", 223, Rarity.MYTHIC, mage.cards.s.ShikoParagonOfTheWay.class)); cards.add(new SetCardInfo("Shock Brigade", 120, Rarity.COMMON, mage.cards.s.ShockBrigade.class)); cards.add(new SetCardInfo("Shocking Sharpshooter", 121, Rarity.UNCOMMON, mage.cards.s.ShockingSharpshooter.class)); + cards.add(new SetCardInfo("Sibsig Appraiser", 56, Rarity.COMMON, mage.cards.s.SibsigAppraiser.class)); cards.add(new SetCardInfo("Sinkhole Surveyor", 93, Rarity.RARE, mage.cards.s.SinkholeSurveyor.class)); cards.add(new SetCardInfo("Skirmish Rhino", 224, Rarity.UNCOMMON, mage.cards.s.SkirmishRhino.class)); cards.add(new SetCardInfo("Smile at Death", 24, Rarity.MYTHIC, mage.cards.s.SmileAtDeath.class)); cards.add(new SetCardInfo("Snakeskin Veil", 159, Rarity.COMMON, mage.cards.s.SnakeskinVeil.class)); + cards.add(new SetCardInfo("Snowmelt Stag", 57, Rarity.COMMON, mage.cards.s.SnowmeltStag.class)); + cards.add(new SetCardInfo("Songcrafter Mage", 225, Rarity.RARE, mage.cards.s.SongcrafterMage.class)); + cards.add(new SetCardInfo("Sonic Shrieker", 226, Rarity.UNCOMMON, mage.cards.s.SonicShrieker.class)); cards.add(new SetCardInfo("Spectral Denial", 58, Rarity.UNCOMMON, mage.cards.s.SpectralDenial.class)); + cards.add(new SetCardInfo("Stadium Headliner", 122, Rarity.RARE, mage.cards.s.StadiumHeadliner.class)); + cards.add(new SetCardInfo("Static Snare", 26, Rarity.UNCOMMON, mage.cards.s.StaticSnare.class)); + cards.add(new SetCardInfo("Stormbeacon Blade", 27, Rarity.UNCOMMON, mage.cards.s.StormbeaconBlade.class)); cards.add(new SetCardInfo("Stormplain Detainment", 28, Rarity.COMMON, mage.cards.s.StormplainDetainment.class)); cards.add(new SetCardInfo("Stormscale Scion", 123, Rarity.MYTHIC, mage.cards.s.StormscaleScion.class)); cards.add(new SetCardInfo("Sultai Devotee", 160, Rarity.COMMON, mage.cards.s.SultaiDevotee.class)); @@ -150,13 +193,20 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Sunset Strikemaster", 126, Rarity.UNCOMMON, mage.cards.s.SunsetStrikemaster.class)); cards.add(new SetCardInfo("Swamp", 281, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swiftwater Cliffs", 268, Rarity.COMMON, mage.cards.s.SwiftwaterCliffs.class)); + cards.add(new SetCardInfo("Teeming Dragonstorm", 30, Rarity.UNCOMMON, mage.cards.t.TeemingDragonstorm.class)); cards.add(new SetCardInfo("Tempest Hawk", 31, Rarity.COMMON, mage.cards.t.TempestHawk.class)); cards.add(new SetCardInfo("Temur Devotee", 61, Rarity.COMMON, mage.cards.t.TemurDevotee.class)); cards.add(new SetCardInfo("Temur Monument", 248, Rarity.UNCOMMON, mage.cards.t.TemurMonument.class)); cards.add(new SetCardInfo("Temur Tawnyback", 229, Rarity.COMMON, mage.cards.t.TemurTawnyback.class)); + cards.add(new SetCardInfo("The Sibsig Ceremony", 91, Rarity.RARE, mage.cards.t.TheSibsigCeremony.class)); cards.add(new SetCardInfo("Thornwood Falls", 269, Rarity.COMMON, mage.cards.t.ThornwoodFalls.class)); + cards.add(new SetCardInfo("Thunder of Unity", 231, Rarity.RARE, mage.cards.t.ThunderOfUnity.class)); + cards.add(new SetCardInfo("Trade Route Envoy", 163, Rarity.COMMON, mage.cards.t.TradeRouteEnvoy.class)); cards.add(new SetCardInfo("Tranquil Cove", 270, Rarity.COMMON, mage.cards.t.TranquilCove.class)); + cards.add(new SetCardInfo("Traveling Botanist", 164, Rarity.UNCOMMON, mage.cards.t.TravelingBotanist.class)); + cards.add(new SetCardInfo("Twin Bolt", 128, Rarity.COMMON, mage.cards.t.TwinBolt.class)); cards.add(new SetCardInfo("Ugin, Eye of the Storms", 1, Rarity.MYTHIC, mage.cards.u.UginEyeOfTheStorms.class)); + cards.add(new SetCardInfo("Unburied Earthcarver", 95, Rarity.COMMON, mage.cards.u.UnburiedEarthcarver.class)); cards.add(new SetCardInfo("Underfoot Underdogs", 129, Rarity.COMMON, mage.cards.u.UnderfootUnderdogs.class)); cards.add(new SetCardInfo("Undergrowth Leopard", 165, Rarity.COMMON, mage.cards.u.UndergrowthLeopard.class)); cards.add(new SetCardInfo("Unending Whisper", 62, Rarity.COMMON, mage.cards.u.UnendingWhisper.class)); @@ -165,14 +215,21 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Unsparing Boltcaster", 130, Rarity.UNCOMMON, mage.cards.u.UnsparingBoltcaster.class)); cards.add(new SetCardInfo("Ureni's Rebuff", 63, Rarity.UNCOMMON, mage.cards.u.UrenisRebuff.class)); cards.add(new SetCardInfo("Venerated Stormsinger", 97, Rarity.UNCOMMON, mage.cards.v.VeneratedStormsinger.class)); + cards.add(new SetCardInfo("Veteran Ice Climber", 64, Rarity.UNCOMMON, mage.cards.v.VeteranIceClimber.class)); cards.add(new SetCardInfo("Voice of Victory", 33, Rarity.RARE, mage.cards.v.VoiceOfVictory.class)); + cards.add(new SetCardInfo("War Effort", 131, Rarity.UNCOMMON, mage.cards.w.WarEffort.class)); cards.add(new SetCardInfo("Watcher of the Wayside", 249, Rarity.COMMON, mage.cards.w.WatcherOfTheWayside.class)); + cards.add(new SetCardInfo("Wayspeaker Bodyguard", 34, Rarity.UNCOMMON, mage.cards.w.WayspeakerBodyguard.class)); + cards.add(new SetCardInfo("Wild Ride", 132, Rarity.COMMON, mage.cards.w.WildRide.class)); cards.add(new SetCardInfo("Wind-Scarred Crag", 271, Rarity.COMMON, mage.cards.w.WindScarredCrag.class)); + cards.add(new SetCardInfo("Wingblade Disciple", 65, Rarity.UNCOMMON, mage.cards.w.WingbladeDisciple.class)); cards.add(new SetCardInfo("Wingspan Stride", 66, Rarity.COMMON, mage.cards.w.WingspanStride.class)); cards.add(new SetCardInfo("Winternight Stories", 67, Rarity.RARE, mage.cards.w.WinternightStories.class)); cards.add(new SetCardInfo("Worthy Cost", 99, Rarity.COMMON, mage.cards.w.WorthyCost.class)); + cards.add(new SetCardInfo("Yathan Roadwatcher", 236, Rarity.RARE, mage.cards.y.YathanRoadwatcher.class)); cards.add(new SetCardInfo("Yathan Tombguard", 100, Rarity.UNCOMMON, mage.cards.y.YathanTombguard.class)); cards.add(new SetCardInfo("Zurgo's Vanguard", 133, Rarity.UNCOMMON, mage.cards.z.ZurgosVanguard.class)); + cards.add(new SetCardInfo("Zurgo, Thunder's Decree", 237, Rarity.RARE, mage.cards.z.ZurgoThundersDecree.class)); cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName())); } diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstormCommander.java b/Mage.Sets/src/mage/sets/TarkirDragonstormCommander.java index f87dc17574a..15997a8fce0 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstormCommander.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstormCommander.java @@ -304,6 +304,8 @@ public final class TarkirDragonstormCommander extends ExpansionSet { cards.add(new SetCardInfo("Temur Ascendancy", 305, Rarity.RARE, mage.cards.t.TemurAscendancy.class)); cards.add(new SetCardInfo("Terramorphic Expanse", 408, Rarity.COMMON, mage.cards.t.TerramorphicExpanse.class)); cards.add(new SetCardInfo("Territorial Hellkite", 240, Rarity.RARE, mage.cards.t.TerritorialHellkite.class)); + cards.add(new SetCardInfo("Teval's Judgment", 28, Rarity.RARE, mage.cards.t.TevalsJudgment.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Teval's Judgment", 68, Rarity.RARE, mage.cards.t.TevalsJudgment.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Teval, the Balanced Scale", 8, Rarity.MYTHIC, mage.cards.t.TevalTheBalancedScale.class)); cards.add(new SetCardInfo("Thalisse, Reverent Medium", 306, Rarity.UNCOMMON, mage.cards.t.ThalisseReverentMedium.class)); cards.add(new SetCardInfo("Think Twice", 168, Rarity.COMMON, mage.cards.t.ThinkTwice.class)); diff --git a/Mage.Sets/src/mage/sets/UnknownEvent.java b/Mage.Sets/src/mage/sets/UnknownEvent.java index 776949d124a..21975fb4b22 100644 --- a/Mage.Sets/src/mage/sets/UnknownEvent.java +++ b/Mage.Sets/src/mage/sets/UnknownEvent.java @@ -1,4 +1,3 @@ - package mage.sets; import mage.cards.ExpansionSet; @@ -17,7 +16,7 @@ public final class UnknownEvent extends ExpansionSet { } private UnknownEvent() { - super("Unknown Event", "DA1", ExpansionSet.buildDate(2023, 2, 15), SetType.JOKE_SET); + super("Unknown Event", "UNK", ExpansionSet.buildDate(2023, 2, 15), SetType.JOKE_SET); this.hasBasicLands = false; this.hasBoosters = false; diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/AfflictTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/AfflictTest.java index 25cd66fa768..0ed11cc3005 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/AfflictTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/AfflictTest.java @@ -5,6 +5,8 @@ import mage.constants.Zone; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; +import static org.mage.test.player.TestPlayer.CHOICE_SKIP; + public class AfflictTest extends CardTestPlayerBase { private final String khenra = "Khenra Eternal"; @@ -35,7 +37,7 @@ public class AfflictTest extends CardTestPlayerBase { attack(1, playerA, khenra); block(1, playerB, elves + ":0", khenra); block(1, playerB, elves + ":1", khenra); - setChoice(playerA, "X=1"); // assign damage + setChoice(playerA, CHOICE_SKIP); // Assign default damage setStrictChooseMode(true); setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BandingTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BandingTest.java new file mode 100644 index 00000000000..ecd2da9036a --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BandingTest.java @@ -0,0 +1,104 @@ +package org.mage.test.cards.abilities.keywords; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author notgreat + */ +public class BandingTest extends CardTestPlayerBase { + + @Test + public void BandingAttackSimple() { + addCard(Zone.BATTLEFIELD, playerA, "Squire"); // 1/2 + addCard(Zone.BATTLEFIELD, playerA, "Benalish Infantry"); // Banding 1/3 + addCard(Zone.BATTLEFIELD, playerA, "Eager Cadet"); // 1/1 + + addCard(Zone.BATTLEFIELD, playerB, "Naga Eternal"); // 3/2 + + attack(1, playerA, "Squire"); + attack(1, playerA, "Benalish Infantry"); + attack(1, playerA, "Eager Cadet"); + setChoice(playerA, true); + setChoice(playerA, "Squire"); + block(1, playerB, "Naga Eternal", "Squire"); + setChoiceAmount(playerA, 1, 2); //1 to Squire, 2 to Infantry, attacking player chooses + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerA, 0); + assertDamageReceived(playerA, "Squire", 1); + assertDamageReceived(playerA, "Benalish Infantry", 2); + assertGraveyardCount(playerB, 1); + assertLife(playerB, 19); // Only Eager Cadet gets through + } + + @Test + public void BandingBlockSimple() { + addCard(Zone.BATTLEFIELD, playerA, "Alpine Grizzly"); // 4/2 + addCard(Zone.BATTLEFIELD, playerB, "Squire"); // 1/2 + addCard(Zone.BATTLEFIELD, playerB, "Sanctuary Cat"); // 1/2 + addCard(Zone.BATTLEFIELD, playerB, "Benalish Infantry"); // Banding 1/3 + + attack(1, playerA, "Alpine Grizzly"); + block(1, playerB, "Squire", "Alpine Grizzly"); + block(1, playerB, "Sanctuary Cat", "Alpine Grizzly"); + block(1, playerB, "Benalish Infantry", "Alpine Grizzly"); + setChoiceAmount(playerB, 1, 1, 2); //1 to Squire, 1 to Cat, 2 to Infantry, defending player chooses + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerA, 1); + assertGraveyardCount(playerB, 0); + assertDamageReceived(playerB, "Squire", 1); + assertDamageReceived(playerB, "Sanctuary Cat", 1); + assertDamageReceived(playerB, "Benalish Infantry", 2); + assertLife(playerB, 20); + + } + + @Test + public void DoubleBanding() { + addCard(Zone.BATTLEFIELD, playerA, "Benalish Infantry"); // Banding 1/3 + addCard(Zone.BATTLEFIELD, playerA, "Fortress Crab"); // 1/6 + addCard(Zone.BATTLEFIELD, playerA, "Eager Cadet"); // 1/1 + + addCard(Zone.BATTLEFIELD, playerB, "Catacomb Slug"); // 2/6 + addCard(Zone.BATTLEFIELD, playerB, "War Elephant"); // Banding 2/2 Trample + + attack(1, playerA, "Benalish Infantry"); + attack(1, playerA, "Fortress Crab"); + attack(1, playerA, "Eager Cadet"); + setChoice(playerA, true); + setChoice(playerA, "Fortress Crab"); + + block(1, playerB, "Catacomb Slug", "Benalish Infantry"); + block(1, playerB, "War Elephant", "Benalish Infantry"); + + setChoiceAmount(playerB, 0, 1); // Damage from Benalish Infantry + setChoiceAmount(playerB, 0, 1); // Damage from Fortress Crab + + setChoiceAmount(playerA, 1, 1); // Damage from War Elephant + setChoiceAmount(playerA, 0, 2); // Damage from Catacomb Slug + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerA, 0); + assertDamageReceived(playerA, "Benalish Infantry", 1); + assertDamageReceived(playerA, "Fortress Crab", 3); + + assertGraveyardCount(playerB, "War Elephant", 1); + assertDamageReceived(playerB, "Catacomb Slug", 0); + + assertLife(playerB, 19); // Only Eager Cadet gets through + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BushidoTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BushidoTest.java index d3c9cbd45a4..6d097cd3152 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BushidoTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BushidoTest.java @@ -5,6 +5,8 @@ import mage.constants.Zone; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; +import static org.mage.test.player.TestPlayer.CHOICE_SKIP; + /** * @author noxx */ @@ -21,6 +23,7 @@ public class BushidoTest extends CardTestPlayerBase { attack(2, playerB, "Isao, Enlightened Bushi"); block(2, playerA, "Elite Vanguard", "Isao, Enlightened Bushi"); + setStrictChooseMode(true); setStopAt(2, PhaseStep.END_COMBAT); execute(); @@ -39,6 +42,7 @@ public class BushidoTest extends CardTestPlayerBase { attack(2, playerB, "Elite Vanguard"); block(2, playerA, "Isao, Enlightened Bushi", "Elite Vanguard"); + setStrictChooseMode(true); setStopAt(2, PhaseStep.END_COMBAT); execute(); @@ -58,9 +62,9 @@ public class BushidoTest extends CardTestPlayerBase { attack(2, playerB, "Isao, Enlightened Bushi"); block(2, playerA, "Llanowar Elves", "Isao, Enlightened Bushi"); block(2, playerA, "Elvish Mystic", "Isao, Enlightened Bushi"); - setChoice(playerB, "X=1"); // assign damage - setChoice(playerB, "X=1"); // assign damage + setChoice(playerB, CHOICE_SKIP); // Assign default damage + setStrictChooseMode(true); setStopAt(2, PhaseStep.END_COMBAT); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/damage/ExcessDamageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/damage/ExcessDamageTest.java index 831b6f77dd8..47e5417a493 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/damage/ExcessDamageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/damage/ExcessDamageTest.java @@ -5,6 +5,8 @@ import mage.constants.Zone; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; +import static org.mage.test.player.TestPlayer.CHOICE_SKIP; + /** * @author TheElk801 */ @@ -158,15 +160,7 @@ public class ExcessDamageTest extends CardTestPlayerBase { block(2, playerA, bear, myrSuperion); block(2, playerA, envoy, myrSuperion); block(2, playerA, bondedConstruct, myrSuperion); - - //Assign this much damage to the first blocking creature - setChoice(playerB, "X=2"); - - //Assign this much damage to the second blocking creature - setChoice(playerB, "X=1"); - - //Assign this much damage to the third blocking creature - setChoice(playerB, "X=1"); + setChoice(playerB, CHOICE_SKIP); // Assign default damage setStrictChooseMode(true); setStopAt(2, PhaseStep.END_TURN); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/emblems/TheRingEmblemTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/emblems/TheRingEmblemTest.java index 4c4afe0424e..e9356c93be4 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/emblems/TheRingEmblemTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/emblems/TheRingEmblemTest.java @@ -15,6 +15,8 @@ import java.util.List; import java.util.Optional; import java.util.stream.Collectors; +import static org.mage.test.player.TestPlayer.CHOICE_SKIP; + /** * @author JayDi85 */ @@ -247,9 +249,10 @@ public class TheRingEmblemTest extends CardTestPlayerBase { attack(3, playerA, "Ashiok's Skulker"); block(3, playerB, "Alabaster Kirin", "Ashiok's Skulker"); block(3, playerB, "Alaborn Trooper", "Ashiok's Skulker"); - setChoice(playerA, "Whenever your Ring-bearer becomes blocked"); // 2x triggers from two blockers - setChoice(playerA, "At end of combat, that permanent"); // 2x triggers from two blockers setChoice(playerA, "Mountain"); // draw/discard on attack trigger + setChoice(playerA, "Whenever your Ring-bearer becomes blocked"); // 2x triggers from two blockers + setChoice(playerA, CHOICE_SKIP); // Assign default damage + setChoice(playerA, "At end of combat, that permanent"); // 2x triggers from two blockers checkPermanentCount("after attack on 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, playerA, "Ashiok's Skulker", 1); checkPermanentCount("after attack on 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, playerB, "Academy Manufactor", 0); checkPermanentCount("after attack on 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, playerB, "Alabaster Kirin", 0); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/prevention/PreventDamageRemoveCountersTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/prevention/PreventDamageRemoveCountersTest.java index 24c35a7b2be..c8918a46f58 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/prevention/PreventDamageRemoveCountersTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/prevention/PreventDamageRemoveCountersTest.java @@ -5,6 +5,8 @@ import mage.constants.Zone; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; +import static org.mage.test.player.TestPlayer.CHOICE_SKIP; + public class PreventDamageRemoveCountersTest extends CardTestPlayerBase { @Test @@ -67,7 +69,7 @@ public class PreventDamageRemoveCountersTest extends CardTestPlayerBase { attack(3, playerA, "Magma Pummeler", playerB); block(3, playerB, "Memnite", "Magma Pummeler"); block(3, playerB, "Goblin Piker", "Magma Pummeler"); - setChoice(playerA, "X=5"); // damage for Pummeler, does not really matter for this test. + setChoice(playerA, CHOICE_SKIP); // Assign default damage addTarget(playerA, playerB); // For the one trigger setStopAt(3, PhaseStep.END_TURN); @@ -117,7 +119,7 @@ public class PreventDamageRemoveCountersTest extends CardTestPlayerBase { attack(3, playerA, "Magma Pummeler", playerB); block(3, playerB, "Centaur Courser", "Magma Pummeler"); block(3, playerB, "Air Elemental", "Magma Pummeler"); - setChoice(playerA, "X=5"); // damage for Pummeler, does not really matter for this test. + setChoice(playerA, CHOICE_SKIP); // Assign default damage addTarget(playerA, playerB); // For the one trigger setStopAt(3, PhaseStep.END_TURN); @@ -148,7 +150,7 @@ public class PreventDamageRemoveCountersTest extends CardTestPlayerBase { attack(1, playerA, "Undergrowth Champion", playerB); block(1, playerB, "Grizzly Bears", "Undergrowth Champion"); block(1, playerB, "Elite Vanguard", "Undergrowth Champion"); - setChoice(playerA, "X=2"); // damage attribution + setChoice(playerA, CHOICE_SKIP); // Assign default damage setStopAt(1, PhaseStep.END_COMBAT); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/fdn/RiteOfPassageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/fdn/RiteOfPassageTest.java index 6f1035cc025..a2c4f36613f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/fdn/RiteOfPassageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/fdn/RiteOfPassageTest.java @@ -6,6 +6,8 @@ import mage.counters.CounterType; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; +import static org.mage.test.player.TestPlayer.CHOICE_SKIP; + public class RiteOfPassageTest extends CardTestPlayerBase { @@ -38,12 +40,7 @@ public class RiteOfPassageTest extends CardTestPlayerBase { attack(1, playerA, "Watchwolf", playerB); block(1, playerB, "Memnite", "Watchwolf"); block(1, playerB, "Agent of Stromgald", "Watchwolf"); - - // Assign this much damage to Memnite - setChoice(playerA, "X=1"); - - // Assign this much damage to Agent of Stromgald - setChoice(playerA, "X=1"); + setChoice(playerA, CHOICE_SKIP); setStopAt(1, PhaseStep.END_TURN); setStrictChooseMode(true); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mir/BindingAgonyTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mir/BindingAgonyTest.java index 9360089029e..70bd6aca5dd 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/mir/BindingAgonyTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mir/BindingAgonyTest.java @@ -5,6 +5,8 @@ import mage.constants.Zone; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; +import static org.mage.test.player.TestPlayer.CHOICE_SKIP; + /** * @author Susucr */ @@ -33,7 +35,9 @@ public class BindingAgonyTest extends CardTestPlayerBase { attack(1, playerA, "Grizzly Bears"); block(1, playerB, "Centaur Courser", "Grizzly Bears"); block(1, playerB, "Memnite", "Grizzly Bears"); + setChoice(playerA, CHOICE_SKIP); // Assign default damage + setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); @@ -53,6 +57,7 @@ public class BindingAgonyTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, agony, "Grizzly Bears", true); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Grizzly Bears"); + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/pip/BloatflySwarmTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/pip/BloatflySwarmTest.java index 18669190a78..e34500b79c8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/pip/BloatflySwarmTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/pip/BloatflySwarmTest.java @@ -6,6 +6,8 @@ import mage.counters.CounterType; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; +import static org.mage.test.player.TestPlayer.CHOICE_SKIP; + /** * @author Susucr */ @@ -32,6 +34,7 @@ public class BloatflySwarmTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, swarm, true); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", swarm); + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -55,7 +58,9 @@ public class BloatflySwarmTest extends CardTestPlayerBase { attack(1, playerA, swarm); block(1, playerB, "Brimstone Dragon", swarm); block(1, playerB, "Giant Spider", swarm); + setChoice(playerA, CHOICE_SKIP); // Assign default damage + setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); @@ -79,8 +84,9 @@ public class BloatflySwarmTest extends CardTestPlayerBase { attack(1, playerA, swarm); block(1, playerB, "Wind Drake", swarm); block(1, playerB, "Giant Spider", swarm); - setChoice(playerA, "X=5"); // damage attribution + setChoice(playerA, CHOICE_SKIP); // Assign default damage + setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/sth/WallOfEssenceTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/sth/WallOfEssenceTest.java index 2048a9ea9f7..b2d10bbb30c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/sth/WallOfEssenceTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/sth/WallOfEssenceTest.java @@ -48,7 +48,7 @@ public class WallOfEssenceTest extends CardTestPlayerBase { block(1, playerB, "Memnite", "Grizzly Bears"); block(1, playerB, wall, "Grizzly Bears"); - setChoice(playerA, "X=2"); // 2 damage on Memnite, no damage to Wall + setChoiceAmount(playerA, 2, 0); // 2 damage on Memnite, no damage to Wall setStopAt(1, PhaseStep.END_TURN); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/tsp/PhantomWurmTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/tsp/PhantomWurmTest.java index 0e64acdd57b..4467b893c77 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/tsp/PhantomWurmTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/tsp/PhantomWurmTest.java @@ -6,6 +6,8 @@ import mage.counters.CounterType; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; +import static org.mage.test.player.TestPlayer.CHOICE_SKIP; + /** * @author Susucr */ @@ -31,9 +33,7 @@ public class PhantomWurmTest extends CardTestPlayerBase { attack(1, playerA, wurm, playerB); block(1, playerB, "Memnite", wurm); block(1, playerB, "Eager Cadet", wurm); - - setChoice(playerA, "X=1"); // damage assignment - setChoice(playerA, "X=3"); // damage assignment + setChoice(playerA, CHOICE_SKIP); // Assign default damage setStopAt(1, PhaseStep.END_TURN); execute(); @@ -115,9 +115,7 @@ public class PhantomWurmTest extends CardTestPlayerBase { attack(1, playerA, wurm, playerB); block(1, playerB, "Memnite", wurm); block(1, playerB, "Goblin Striker", wurm); - - setChoice(playerA, "X=1"); // damage assignment - setChoice(playerA, "X=3"); // damage assignment + setChoice(playerA, CHOICE_SKIP); // Assign default damage setStopAt(1, PhaseStep.END_TURN); execute(); @@ -139,9 +137,7 @@ public class PhantomWurmTest extends CardTestPlayerBase { attack(1, playerA, wurm, playerB); block(1, playerB, "Boros Recruit", wurm); block(1, playerB, "Goblin Striker", wurm); - - setChoice(playerA, "X=1"); // damage assignment - setChoice(playerA, "X=3"); // damage assignment + setChoice(playerA, CHOICE_SKIP); // Assign default damage setStopAt(1, PhaseStep.END_TURN); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/targets/TargetMultiAmountTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/targets/TargetMultiAmountTest.java index 06b8129f704..12ab9202cfe 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/targets/TargetMultiAmountTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/targets/TargetMultiAmountTest.java @@ -57,7 +57,7 @@ public class TargetMultiAmountTest extends CardTestPlayerBaseWithAIHelps { private void assertDefaultValuesUnconstrained(String need, int count, int min, int max) { List constraints = getUnconstrainedConstraints(count); - List defaultValues = MultiAmountType.prepareDefaltValues(constraints, min, max); + List defaultValues = MultiAmountType.prepareDefaultValues(constraints, min, max); String current = defaultValues .stream() .map(String::valueOf) @@ -122,7 +122,7 @@ public class TargetMultiAmountTest extends CardTestPlayerBaseWithAIHelps { getUnconstrainedConstraints(4)); // good values are checking in test_DefaultValues, it's an additional - List list = MultiAmountType.prepareDefaltValues(constraints.get(3), 0, 0); + List list = MultiAmountType.prepareDefaultValues(constraints.get(3), 0, 0); // count (0, 0, 0) Assert.assertFalse("count", MultiAmountType.isGoodValues(list, constraints.get(0), 0, 0)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/damage/DonnaNobleTests.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/damage/DonnaNobleTests.java index 826afcc4757..01c72e5f8ef 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/damage/DonnaNobleTests.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/damage/DonnaNobleTests.java @@ -5,6 +5,8 @@ import mage.constants.Zone; import org.junit.Test; import org.mage.test.serverside.base.CardTestCommander4Players; +import static org.mage.test.player.TestPlayer.CHOICE_SKIP; + /** * * @author jimga150 @@ -32,12 +34,7 @@ public class DonnaNobleTests extends CardTestCommander4Players { attack(5, playerA, "Impervious Greatwurm", playerB); block(5, playerB, "Memnite", "Impervious Greatwurm"); block(5, playerB, "Expedition Envoy", "Impervious Greatwurm"); - - //Assign this much damage to the first blocking creature - setChoice(playerA, "X=1"); - - //Assign this much damage to the second blocking creature - setChoice(playerA, "X=1"); + setChoice(playerA, CHOICE_SKIP); // Assign default damage //Target this player with Donna Noble addTarget(playerA, playerB); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/delayed/DamagedBatchTests.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/delayed/DamagedBatchTests.java index e4c30fd1535..2d7f9422924 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/delayed/DamagedBatchTests.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/delayed/DamagedBatchTests.java @@ -6,6 +6,8 @@ import mage.constants.Zone; import org.junit.Test; import org.mage.test.serverside.base.CardTestCommander4Players; +import static org.mage.test.player.TestPlayer.CHOICE_SKIP; + /** * * @author jimga150 @@ -25,9 +27,7 @@ public class DamagedBatchTests extends CardTestCommander4Players { attack(1, playerA, "Donna Noble", playerB); block(1, playerB, "Memnite", "Donna Noble"); block(1, playerB, "Expedition Envoy", "Donna Noble"); - - //Assign this much damage to the first blocking creature - setChoice(playerA, "X=1"); + setChoice(playerA, CHOICE_SKIP); // Assign default damage //Target this player with Donna Noble addTarget(playerA, playerB); diff --git a/Mage.Tests/src/test/java/org/mage/test/combat/AttackBlockRestrictionsTest.java b/Mage.Tests/src/test/java/org/mage/test/combat/AttackBlockRestrictionsTest.java index a43818f1c90..f64f6bf89a5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/combat/AttackBlockRestrictionsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/combat/AttackBlockRestrictionsTest.java @@ -11,6 +11,7 @@ import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import static org.mage.test.player.TestPlayer.CHOICE_SKIP; /** * Test restrictions for choosing attackers and blockers. @@ -753,9 +754,9 @@ public class AttackBlockRestrictionsTest extends CardTestPlayerBaseWithAIHelps { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bloodscent", "Sonorous Howlbonder"); attack(1, playerA, "Sonorous Howlbonder"); - setChoiceAmount(playerA, 1); // assign damage to 1 of 3 blocking memnites checkAttackers("x1 attacker", 1, playerA, "Sonorous Howlbonder"); checkBlockers("x3 blockers", 1, playerB, "Memnite", "Memnite", "Memnite"); + setChoice(playerA, CHOICE_SKIP); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -783,7 +784,7 @@ public class AttackBlockRestrictionsTest extends CardTestPlayerBaseWithAIHelps { // ai must choose all blockers anyway attack(1, playerA, "Sonorous Howlbonder"); aiPlayStep(1, PhaseStep.DECLARE_BLOCKERS, playerB); - setChoiceAmount(playerA, 1); // assign damage to 1 of 3 blocking memnites + setChoiceAmount(playerA, 1, 1, 0); // assign damage to blocking memnites checkAttackers("x1 attacker", 1, playerA, "Sonorous Howlbonder"); checkBlockers("x3 blockers", 1, playerB, "Memnite", "Memnite", "Memnite"); @@ -813,9 +814,9 @@ public class AttackBlockRestrictionsTest extends CardTestPlayerBaseWithAIHelps { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bloodscent", "Sonorous Howlbonder"); attack(1, playerA, "Sonorous Howlbonder"); - setChoiceAmount(playerA, 1); // assign damage to 1 of 3 blocking memnites checkAttackers("x1 attacker", 1, playerA, "Sonorous Howlbonder"); checkBlockers("all blockers", 1, playerB, "Memnite", "Memnite", "Memnite", "Memnite", "Memnite"); + setChoice(playerA, CHOICE_SKIP); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -845,7 +846,7 @@ public class AttackBlockRestrictionsTest extends CardTestPlayerBaseWithAIHelps { // ai must choose all blockers attack(1, playerA, "Sonorous Howlbonder"); aiPlayStep(1, PhaseStep.DECLARE_BLOCKERS, playerB); - setChoiceAmount(playerA, 1); // assign damage to 1 of 3 blocking memnites + setChoiceAmount(playerA, 1, 1, 0, 0, 0); // assign damage to blocking memnites checkAttackers("x1 attacker", 1, playerA, "Sonorous Howlbonder"); checkBlockers("all blockers", 1, playerB, "Memnite", "Memnite", "Memnite", "Memnite", "Memnite"); @@ -879,7 +880,6 @@ public class AttackBlockRestrictionsTest extends CardTestPlayerBaseWithAIHelps { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bloodscent", "Sonorous Howlbonder"); attack(1, playerA, "Sonorous Howlbonder"); - setChoiceAmount(playerA, 1); // assign damage to 1 of 3 blocking memnites checkAttackers("x1 attacker", 1, playerA, "Sonorous Howlbonder"); checkBlockers("one possible blocker", 1, playerB, "Memnite"); @@ -998,8 +998,7 @@ public class AttackBlockRestrictionsTest extends CardTestPlayerBaseWithAIHelps { addTarget(playerA, "Alley Strangler"); // boost target setChoice(playerA, true); // boost target attack(1, playerA, "Alley Strangler"); - setChoiceAmount(playerA, 1); // assign damage to 1 of 2 blocking memnites - setChoiceAmount(playerA, 1); // assign damage to 2 of 2 blocking memnites + setChoiceAmount(playerA, 1, 1); // assign damage to blocking memnites aiPlayStep(1, PhaseStep.DECLARE_BLOCKERS, playerB); checkAttackers("x1 attacker", 1, playerA, "Alley Strangler"); checkBlockers("x2 blockers", 1, playerB, "Memnite", "Memnite"); diff --git a/Mage.Tests/src/test/java/org/mage/test/combat/DamageDistributionTest.java b/Mage.Tests/src/test/java/org/mage/test/combat/DamageDistributionTest.java index c4f4c2218b2..6484c53cf75 100644 --- a/Mage.Tests/src/test/java/org/mage/test/combat/DamageDistributionTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/combat/DamageDistributionTest.java @@ -197,4 +197,35 @@ public class DamageDistributionTest extends CardTestPlayerBase { assertLife(playerB, 20 - 5); } + + @Test + public void test2x2Block() { + addCard(Zone.BATTLEFIELD, playerA, "Catacomb Slug"); // 2/6 + addCard(Zone.BATTLEFIELD, playerA, "Catacomb Crocodile"); // 3/7 + + addCard(Zone.BATTLEFIELD, playerB, "Brave the Sands"); //can block 2 + addCard(Zone.BATTLEFIELD, playerB, "Marsh Hulk"); // 4/6 + addCard(Zone.BATTLEFIELD, playerB, "Fortress Crab"); // 1/6 + + attack(1, playerA, "Catacomb Slug"); + attack(1, playerA, "Catacomb Crocodile"); + block(1, playerB, "Fortress Crab", "Catacomb Slug"); + block(1, playerB, "Fortress Crab", "Catacomb Crocodile"); + block(1, playerB, "Marsh Hulk", "Catacomb Slug"); + block(1, playerB, "Marsh Hulk", "Catacomb Crocodile"); + + setChoiceAmount(playerA, 1, 1); // Catacomb Slug + setChoiceAmount(playerA, 1, 2); // Catacomb Crocodile + setChoiceAmount(playerB, 1, 0); // Fortress Crab + setChoiceAmount(playerB, 2, 2); // Marsh Hulk + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + + assertDamageReceived(playerA, "Catacomb Slug", 3); + assertDamageReceived(playerA, "Catacomb Crocodile", 2); + assertDamageReceived(playerB, "Fortress Crab", 2); + assertDamageReceived(playerB, "Marsh Hulk", 3); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/combat/LifelinkInCombatTest.java b/Mage.Tests/src/test/java/org/mage/test/combat/LifelinkInCombatTest.java index 2881b195b43..aaeb74c2ec2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/combat/LifelinkInCombatTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/combat/LifelinkInCombatTest.java @@ -5,6 +5,8 @@ import mage.constants.Zone; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; +import static org.mage.test.player.TestPlayer.CHOICE_SKIP; + public class LifelinkInCombatTest extends CardTestPlayerBase { @Test public void testOneBlockerTrample() { @@ -43,8 +45,7 @@ public class LifelinkInCombatTest extends CardTestPlayerBase { attack(1, playerA, "Brion Stoutarm"); block(1, playerB, "Boros Recruit", "Brion Stoutarm"); block(1, playerB, "Suntail Hawk", "Brion Stoutarm"); - setChoice(playerA, "X=1"); // Damage assignment - setChoice(playerA, "X=1"); // Damage assignment + setChoice(playerA, CHOICE_SKIP); // Assign default damage addTarget(playerA, "Brion Stoutarm"); setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 15dfcd42146..e33796e3a0f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -2975,11 +2975,12 @@ public class TestPlayer implements Player { assertAliasSupportInChoices(false); int needCount = messages.size(); - List defaultList = MultiAmountType.prepareDefaltValues(messages, totalMin, totalMax); + List defaultList = MultiAmountType.prepareDefaultValues(messages, totalMin, totalMax); if (needCount == 0) { return defaultList; } + List answer = new ArrayList<>(defaultList); if (!choices.isEmpty()) { // must fill all possible choices or skip it @@ -4477,19 +4478,6 @@ public class TestPlayer implements Player { return computerPlayer.playMana(ability, unpaid, promptText, game); } - @Override - public UUID chooseAttackerOrder(List attacker, Game game - ) { - return computerPlayer.chooseAttackerOrder(attacker, game); - } - - @Override - public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, - List blockerOrder, Game game - ) { - return computerPlayer.chooseBlockerOrder(blockers, combatGroup, blockerOrder, game); - } - @Override public void sideboard(Match match, Deck deck ) { diff --git a/Mage/src/main/java/mage/abilities/common/PayMoreToCastAsThoughtItHadFlashAbility.java b/Mage/src/main/java/mage/abilities/common/PayMoreToCastAsThoughtItHadFlashAbility.java index 0ba8afb443a..f27112aba7f 100644 --- a/Mage/src/main/java/mage/abilities/common/PayMoreToCastAsThoughtItHadFlashAbility.java +++ b/Mage/src/main/java/mage/abilities/common/PayMoreToCastAsThoughtItHadFlashAbility.java @@ -16,24 +16,30 @@ import mage.util.CardUtil; public class PayMoreToCastAsThoughtItHadFlashAbility extends SpellAbility { private final Cost costsToAdd; + private final String rule; public PayMoreToCastAsThoughtItHadFlashAbility(Card card, Cost costsToAdd) { + this(card, costsToAdd, null); + } + + public PayMoreToCastAsThoughtItHadFlashAbility(Card card, Cost costsToAdd, String rule) { super(card.getSpellAbility().getManaCosts().copy(), card.getName(), Zone.HAND, SpellAbilityType.BASE_ALTERNATE); this.costsToAdd = costsToAdd; + this.rule = rule; this.timing = TimingRule.INSTANT; this.setRuleAtTheTop(true); - if(costsToAdd instanceof ManaCosts) { + if (costsToAdd instanceof ManaCosts) { ManaCosts manaCosts = (ManaCosts) costsToAdd; CardUtil.increaseCost(this, manaCosts); - } - else { + } else { this.addCost(costsToAdd); } } protected PayMoreToCastAsThoughtItHadFlashAbility(final PayMoreToCastAsThoughtItHadFlashAbility ability) { super(ability); + this.rule = ability.rule; this.costsToAdd = ability.costsToAdd; } @@ -46,8 +52,12 @@ public class PayMoreToCastAsThoughtItHadFlashAbility extends SpellAbility { public String getRule(boolean all) { return getRule(); } + @Override public String getRule() { + if (rule != null && !rule.isEmpty()) { + return rule; + } if (costsToAdd instanceof ManaCosts) { return "You may cast {this} as though it had flash if you pay " + costsToAdd.getText() + " more to cast it. (You may cast it any time you could cast an instant.)"; } else { @@ -55,4 +65,4 @@ public class PayMoreToCastAsThoughtItHadFlashAbility extends SpellAbility { } } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/constants/MultiAmountType.java b/Mage/src/main/java/mage/constants/MultiAmountType.java index ed5b1d5b34b..398ca7a0fd8 100644 --- a/Mage/src/main/java/mage/constants/MultiAmountType.java +++ b/Mage/src/main/java/mage/constants/MultiAmountType.java @@ -8,23 +8,24 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; -public enum MultiAmountType { +public class MultiAmountType { - MANA("Add mana", "Distribute mana among colors"), - DAMAGE("Assign damage", "Assign damage among targets"), - P1P1("Add +1/+1 counters", "Distribute +1/+1 counters among creatures"), - COUNTERS("Choose counters", "Move counters"), - CHEAT_LANDS("Choose lands", "Add lands to your battlefield", true); + public static final MultiAmountType MANA = new MultiAmountType("Add mana", "Distribute mana among colors"); + public static final MultiAmountType DAMAGE = new MultiAmountType("Assign damage", "Assign damage among targets"); + + public static final MultiAmountType P1P1 = new MultiAmountType("Add +1/+1 counters", "Distribute +1/+1 counters among creatures"); + public static final MultiAmountType COUNTERS = new MultiAmountType("Choose counters", "Move counters"); + public static final MultiAmountType CHEAT_LANDS = new MultiAmountType("Choose lands", "Add lands to your battlefield", true); private final String title; private final String header; private final boolean canCancel; // choice dialog will return null instead default values - MultiAmountType(String title, String header) { + public MultiAmountType(String title, String header) { this(title, header, false); } - MultiAmountType(String title, String header, boolean canCancel) { + public MultiAmountType(String title, String header, boolean canCancel) { this.title = title; this.header = header; this.canCancel = canCancel; @@ -42,7 +43,7 @@ public enum MultiAmountType { return canCancel; } - public static List prepareDefaltValues(List constraints, int min, int max) { + public static List prepareDefaultValues(List constraints, int min, int max) { // default values must be assigned from first to last by minimum values List res = constraints.stream().map(m -> m.defaultValue > Integer.MIN_VALUE ? m.defaultValue : Math.min(0, max)) .collect(Collectors.toList()); @@ -50,7 +51,7 @@ public enum MultiAmountType { return res; } - int total = res.stream().mapToInt(x -> x).sum();; + int total = res.stream().mapToInt(x -> x).sum(); // Fill values until we reach the overall minimum. Do this by filling values up until either their max or however much is leftover, starting with the first option. if (min > 0 && total < min) { @@ -174,7 +175,7 @@ public enum MultiAmountType { // data check if (returnDefaultOnError && !isGoodValues(res, constraints, min, max)) { // on broken data - return default - return prepareDefaltValues(constraints, min, max); + return prepareDefaultValues(constraints, min, max); } return res; diff --git a/Mage/src/main/java/mage/game/combat/Combat.java b/Mage/src/main/java/mage/game/combat/Combat.java index 91637785533..333e786b95a 100644 --- a/Mage/src/main/java/mage/game/combat/Combat.java +++ b/Mage/src/main/java/mage/game/combat/Combat.java @@ -60,7 +60,7 @@ public class Combat implements Serializable, Copyable { protected List groups = new ArrayList<>(); protected List formerGroups = new ArrayList<>(); - protected Map blockingGroups = new HashMap<>(); + protected Map blockingGroups = new LinkedHashMap<>(); // all possible defenders (players, planeswalkers or battle) protected Set defenders = new HashSet<>(); // how many creatures attack defending player @@ -200,7 +200,7 @@ public class Combat implements Serializable, Copyable { StringBuilder sb = new StringBuilder(); sb.append(attackingPlayerId).append(defenders); for (CombatGroup group : groups) { - sb.append(group.defenderId).append(group.attackers).append(group.attackerOrder).append(group.blockers).append(group.blockerOrder); + sb.append(group.defenderId).append(group.attackers).append(group.blockers); } return sb.toString(); } @@ -785,7 +785,7 @@ public class Combat implements Serializable, Copyable { if (attackerExists) { if (!group.getBlockers().isEmpty()) { sb.append("blocked by "); - for (UUID blockingCreatureId : group.getBlockerOrder()) { + for (UUID blockingCreatureId : group.getBlockers()) { Permanent blockingCreature = game.getPermanent(blockingCreatureId); if (blockingCreature != null) { sb.append(blockingCreature.getLogName()).append(" ("); @@ -1799,24 +1799,11 @@ public class Combat implements Serializable, Copyable { return playerDefenders; } - public void damageAssignmentOrder(Game game) { - for (CombatGroup group : groups) { - group.pickBlockerOrder(attackingPlayerId, game); - } - for (Map.Entry blockingGroup : blockingGroups.entrySet()) { - Permanent blocker = game.getPermanent(blockingGroup.getKey()); - if (blocker != null) { - blockingGroup.getValue().pickAttackerOrder(blocker.getControllerId(), game); - } - } - } - @SuppressWarnings("deprecation") public void removeAttacker(UUID attackerId, Game game) { for (CombatGroup group : groups) { if (group.attackers.contains(attackerId)) { group.attackers.remove(attackerId); - group.attackerOrder.remove(attackerId); for (Set attackingCreatures : numberCreaturesDefenderAttackedBy.values()) { attackingCreatures.remove(attackerId); } @@ -1869,7 +1856,6 @@ public class Combat implements Serializable, Copyable { } for (CombatGroup group : groupsToCheck) { group.blockers.remove(blockerId); - group.blockerOrder.remove(blockerId); if (group.blockers.isEmpty()) { group.blocked = false; } @@ -1885,11 +1871,9 @@ public class Combat implements Serializable, Copyable { if (blockGroup.blockers.contains(blockerId)) { for (UUID attackerId : group.getAttackers()) { blockGroup.attackers.remove(attackerId); - blockGroup.attackerOrder.remove(attackerId); } if (creature.getBlocking() == 0) { blockGroup.blockers.remove(blockerId); - blockGroup.attackerOrder.clear(); } } if (blockGroup.blockers.isEmpty()) { @@ -1914,7 +1898,6 @@ public class Combat implements Serializable, Copyable { for (CombatGroup group : groups) { if (group.blockers.contains(blockerId)) { group.blockers.remove(blockerId); - group.blockerOrder.remove(blockerId); if (group.blockers.isEmpty()) { group.blocked = false; } @@ -1924,7 +1907,6 @@ public class Combat implements Serializable, Copyable { for (CombatGroup group : getBlockingGroups()) { if (group.blockers.contains(blockerId)) { group.blockers.remove(blockerId); - group.attackerOrder.clear(); } if (group.blockers.isEmpty()) { canRemove = true; diff --git a/Mage/src/main/java/mage/game/combat/CombatGroup.java b/Mage/src/main/java/mage/game/combat/CombatGroup.java index c7caca995fa..03a492dd05f 100644 --- a/Mage/src/main/java/mage/game/combat/CombatGroup.java +++ b/Mage/src/main/java/mage/game/combat/CombatGroup.java @@ -6,6 +6,7 @@ import mage.abilities.common.ControllerDivideCombatDamageAbility; import mage.abilities.common.DamageAsThoughNotBlockedAbility; import mage.abilities.keyword.*; import mage.constants.AsThoughEffectType; +import mage.constants.MultiAmountType; import mage.constants.Outcome; import mage.filter.StaticFilters; import mage.game.Game; @@ -15,6 +16,7 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.util.Copyable; +import mage.util.MultiAmountMessage; import mage.watchers.common.FirstStrikeWatcher; import java.io.Serializable; @@ -29,8 +31,6 @@ public class CombatGroup implements Serializable, Copyable { protected List attackers = new ArrayList<>(); protected List formerAttackers = new ArrayList<>(); protected List blockers = new ArrayList<>(); - protected List blockerOrder = new ArrayList<>(); - protected List attackerOrder = new ArrayList<>(); protected Map players = new HashMap<>(); protected boolean blocked; protected UUID defenderId; // planeswalker, player, or battle id, can be null after remove from combat (e.g. due damage) @@ -52,8 +52,6 @@ public class CombatGroup implements Serializable, Copyable { this.attackers.addAll(group.attackers); this.formerAttackers.addAll(group.formerAttackers); this.blockers.addAll(group.blockers); - this.blockerOrder.addAll(group.blockerOrder); - this.attackerOrder.addAll(group.attackerOrder); this.players.putAll(group.players); this.blocked = group.blocked; this.defenderId = group.defenderId; @@ -91,10 +89,6 @@ public class CombatGroup implements Serializable, Copyable { return blockers; } - public List getBlockerOrder() { - return blockerOrder; - } - private static boolean hasFirstOrDoubleStrike(Permanent perm) { return hasFirstStrike(perm) || hasDoubleStrike(perm); } @@ -175,7 +169,6 @@ public class CombatGroup implements Serializable, Copyable { if (attacker != null && !assignsDefendingPlayerAndOrDefendingCreaturesDividedDamage(attacker, attacker.getControllerId(), first, game, true)) { if (blockers.isEmpty()) { unblockedDamage(first, game); - return; } else { Player player = game.getPlayer(defenderAssignsCombatDamage(game) ? defendingPlayerId : attacker.getControllerId()); if ((attacker.getAbilities().containsKey(DamageAsThoughNotBlockedAbility.getInstance().getId()) && @@ -186,11 +179,7 @@ public class CombatGroup implements Serializable, Copyable { blocked = false; unblockedDamage(first, game); } - if (blockers.size() == 1) { - singleBlockerDamage(player, first, game); - } else { - multiBlockerDamage(player, first, game); - } + blockerDamage(player, first, game); } } } @@ -206,9 +195,7 @@ public class CombatGroup implements Serializable, Copyable { } } if (attackers.size() != 1) { - multiAttackerDamage(first, game); - // } else { - // singleAttackerDamage(first, game); + attackerDamage(first, game); } } } @@ -269,51 +256,16 @@ public class CombatGroup implements Serializable, Copyable { } } } - - private void singleBlockerDamage(Player player, boolean first, Game game) { - Permanent blocker = game.getPermanent(blockers.get(0)); - Permanent attacker = game.getPermanent(attackers.get(0)); - if (blocker != null && attacker != null) { - int blockerDamage = getDamageValueFromPermanent(blocker, game); // must be set before attacker damage marking because of effects like Test of Faith - if (blocked && dealsDamageThisStep(attacker, first, game)) { - int damage = getDamageValueFromPermanent(attacker, game); - if (hasTrample(attacker)) { - int lethalDamage = getLethalDamage(blocker, attacker, game); - if (lethalDamage >= damage) { - blocker.markDamage(damage, attacker.getId(), null, game, true, true); - } else { - int damageAssigned = player.getAmount(lethalDamage, damage, "Assign damage to " + blocker.getName(), game); - blocker.markDamage(damageAssigned, attacker.getId(), null, game, true, true); - damage -= damageAssigned; - if (damage > 0) { - defenderDamage(attacker, damage, game, false); - } - } - } else { - blocker.markDamage(damage, attacker.getId(), null, game, true, true); - } - } - if (dealsDamageThisStep(blocker, first, game)) { - if (checkSoleBlockerAfter(blocker, game)) { // blocking several creatures handled separately - if (!assignsDefendingPlayerAndOrDefendingCreaturesDividedDamage(blocker, blocker.getControllerId(), first, game, false)) { - attacker.markDamage(blockerDamage, blocker.getId(), null, game, true, true); - } - } - } - } - } - - private void multiBlockerDamage(Player player, boolean first, Game game) { + private void blockerDamage(Player player, boolean first, Game game) { Permanent attacker = game.getPermanent(attackers.get(0)); if (attacker == null) { return; } - boolean oldRuleDamage = (Objects.equals(player.getId(), defendingPlayerId)); int damage = getDamageValueFromPermanent(attacker, game); if (dealsDamageThisStep(attacker, first, game)) { // must be set before attacker damage marking because of effects like Test of Faith Map blockerPower = new HashMap<>(); - for (UUID blockerId : blockerOrder) { + for (UUID blockerId : blockers) { Permanent blocker = game.getPermanent(blockerId); if (dealsDamageThisStep(blocker, first, game)) { if (checkSoleBlockerAfter(blocker, game)) { // blocking several creatures handled separately @@ -322,42 +274,62 @@ public class CombatGroup implements Serializable, Copyable { } } Map assigned = new HashMap<>(); + List damageDivision = new ArrayList<>(); + List blockersCopy = new ArrayList<>(blockers); if (blocked) { - boolean excessDamageToDefender = true; - for (UUID blockerId : new ArrayList<>(blockerOrder)) { // prevent ConcurrentModificationException + int remainingDamage = damage; + for (UUID blockerId : blockers) { Permanent blocker = game.getPermanent(blockerId); if (blocker != null) { - int lethalDamage = getLethalDamage(blocker, attacker, game); - if (lethalDamage >= damage) { - if (!oldRuleDamage) { - assigned.put(blockerId, damage); - damage = 0; - break; - } else if (damage == 0) { - break; - } - } - int damageAssigned = 0; - if (!oldRuleDamage) { - damageAssigned = player.getAmount(lethalDamage, damage, "Assign damage to " + blocker.getName(), game); - } else { - damageAssigned = player.getAmount(0, damage, "Assign damage to " + blocker.getName(), game); - if (damageAssigned < lethalDamage) { - excessDamageToDefender = false; // all blockers need to have lethal damage assigned before it can trample over to the defender - } - } - assigned.put(blockerId, damageAssigned); - damage -= damageAssigned; + int defaultDamage = Math.min(remainingDamage, blocker.getLethalDamage(attacker.getId(), game)); + remainingDamage -= defaultDamage; + String message = String.format("%s, P/T: %d/%d", + blocker.getLogName(), + blocker.getPower().getValue(), + blocker.getToughness().getValue()); + damageDivision.add(new MultiAmountMessage(message, 0, damage, defaultDamage)); } } - if (damage > 0 && hasTrample(attacker) && excessDamageToDefender) { - defenderDamage(attacker, damage, game, false); - } else if (!blockerOrder.isEmpty()) { - // Assign the damage left to first blocker - assigned.put(blockerOrder.get(0), assigned.get(blockerOrder.get(0)) == null ? 0 : assigned.get(blockerOrder.get(0)) + damage); + List amounts; + if (hasTrample(attacker)){ + if (remainingDamage > 0 || damageDivision.size() > 1) { + MultiAmountType dialogue = new MultiAmountType("Assign combat damage (with trample)", + String.format("Assign combat damage among creatures blocking %s, P/T: %d/%d (Unassigned damage tramples through)", + attacker.getLogName(), attacker.getPower().getValue(), attacker.getToughness().getValue())); + amounts = player.getMultiAmountWithIndividualConstraints(Outcome.Damage, damageDivision, damage - remainingDamage, damage, dialogue, game); + } else { + amounts = new ArrayList<>(); + if (damageDivision.size() == 1) { // Assign all damage to one blocker + amounts.add(damage); + } + } + int trampleDamage = damage - (amounts.stream().mapToInt(x -> x).sum()); + if (trampleDamage > 0) { + defenderDamage(attacker, trampleDamage, game, false); + } + } else { + if (remainingDamage > 0){ + damageDivision.get(0).defaultValue += remainingDamage; + } + if (damageDivision.size() > 1) { + MultiAmountType dialogue = new MultiAmountType("Assign combat damage", + String.format("Assign combat damage among creatures blocking %s, P/T: %d/%d", + attacker.getLogName(), attacker.getPower().getValue(), attacker.getToughness().getValue())); + amounts = player.getMultiAmountWithIndividualConstraints(Outcome.Damage, damageDivision, damage, damage, dialogue, game); + } else { + amounts = new LinkedList<>(); + if (damageDivision.size() == 1) { // Assign all damage to one blocker + amounts.add(damage); + } + } + } + if (!damageDivision.isEmpty()){ + for (int i=0; i { } } } else { - for (UUID blockerId : blockerOrder) { + for (UUID blockerId : blockers) { Permanent blocker = game.getPermanent(blockerId); if (dealsDamageThisStep(blocker, first, game)) { if (!assignsDefendingPlayerAndOrDefendingCreaturesDividedDamage(blocker, blocker.getControllerId(), first, game, false)) { @@ -395,7 +367,7 @@ public class CombatGroup implements Serializable, Copyable { if (dealsDamageThisStep(attacker, first, game)) { // must be set before attacker damage marking because of effects like Test of Faith Map blockerPower = new HashMap<>(); - for (UUID blockerId : blockerOrder) { + for (UUID blockerId : blockers) { Permanent blocker = game.getPermanent(blockerId); if (dealsDamageThisStep(blocker, first, game)) { if (checkSoleBlockerAfter(blocker, game)) { // blocking several creatures handled separately @@ -422,7 +394,7 @@ public class CombatGroup implements Serializable, Copyable { } } if (isAttacking) { - for (UUID blockerId : blockerOrder) { + for (UUID blockerId : blockers) { Integer power = blockerPower.get(blockerId); if (power != null) { // might be missing canDamage condition? @@ -439,7 +411,7 @@ public class CombatGroup implements Serializable, Copyable { } } else { if (isAttacking) { - for (UUID blockerId : blockerOrder) { + for (UUID blockerId : blockers) { Permanent blocker = game.getPermanent(blockerId); if (dealsDamageThisStep(blocker, first, game)) { if (!assignsDefendingPlayerAndOrDefendingCreaturesDividedDamage(blocker, blocker.getControllerId(), first, game, false)) { @@ -473,81 +445,62 @@ public class CombatGroup implements Serializable, Copyable { /** * Damages attacking creatures by a creature that blocked several ones * Damages only attackers as blocker was damage in - * {@link #singleBlockerDamage}. + * {@link #blockerDamage}. *

- * Handles abilities like "{this} an block any number of creatures.". - *

- * Blocker damage for blockers blocking single creatures is handled in the - * single/multi blocker methods, so this shouldn't be used anymore. - * - * @param first - * @param game - * @deprecated - */ - @Deprecated - private void singleAttackerDamage(boolean first, Game game) { - Permanent blocker = game.getPermanent(blockers.get(0)); - Permanent attacker = game.getPermanent(attackers.get(0)); - if (blocker != null && attacker != null) { - if (dealsDamageThisStep(blocker, first, game)) { - int damage = getDamageValueFromPermanent(blocker, game); - attacker.markDamage(damage, blocker.getId(), null, game, true, true); - } - } - } - - /** - * Damages attacking creatures by a creature that blocked several ones - * Damages only attackers as blocker was damage in either - * {@link #singleBlockerDamage} or {@link #multiBlockerDamage}. - *

- * Handles abilities like "{this} an block any number of creatures.". + * Handles abilities like "{this} can block any number of creatures.". * * @param first * @param game */ - private void multiAttackerDamage(boolean first, Game game) { + private void attackerDamage(boolean first, Game game) { Permanent blocker = game.getPermanent(blockers.get(0)); if (blocker == null) { return; } - boolean oldRuleDamage = attackerAssignsCombatDamage(game); // handles banding - Player player = game.getPlayer(oldRuleDamage ? game.getCombat().getAttackingPlayerId() : blocker.getControllerId()); + //Handle Banding + Player player = game.getPlayer(attackerAssignsCombatDamage(game) ? game.getCombat().getAttackingPlayerId() : blocker.getControllerId()); int damage = getDamageValueFromPermanent(blocker, game); if (dealsDamageThisStep(blocker, first, game)) { Map assigned = new HashMap<>(); - for (UUID attackerId : attackerOrder) { + List damageDivision = new ArrayList<>(); + List attackersCopy = new ArrayList<>(attackers); + int remainingDamage = damage; + for (UUID attackerId : attackers) { Permanent attacker = game.getPermanent(attackerId); if (attacker != null) { - int lethalDamage = getLethalDamage(attacker, blocker, game); - if (lethalDamage >= damage) { - if (!oldRuleDamage) { - assigned.put(attackerId, damage); - damage = 0; - break; - } else if (damage == 0) { - break; - } - } - int damageAssigned = 0; - if (!oldRuleDamage) { - damageAssigned = player.getAmount(lethalDamage, damage, "Assign damage to " + attacker.getName(), game); - } else { - damageAssigned = player.getAmount(0, damage, "Assign damage to " + attacker.getName(), game); - } - assigned.put(attackerId, damageAssigned); - damage -= damageAssigned; + int defaultDamage = Math.min(remainingDamage, attacker.getLethalDamage(blocker.getId(), game)); + remainingDamage -= defaultDamage; + String message = String.format("%s, P/T: %d/%d", + attacker.getLogName(), + attacker.getPower().getValue(), + attacker.getToughness().getValue()); + damageDivision.add(new MultiAmountMessage(message, 0, damage, defaultDamage)); } } - if (damage > 0) { - // Assign the damage left to first attacker - assigned.put(attackerOrder.get(0), assigned.get(attackerOrder.get(0)) + damage); + List amounts; + if (remainingDamage > 0){ + damageDivision.get(0).defaultValue += remainingDamage; + } + if (damageDivision.size() > 1) { + MultiAmountType dialogue = new MultiAmountType("Assign blocker combat damage", + String.format("Assign combat damage among creatures blocked by %s, P/T: %d/%d", + blocker.getLogName(), blocker.getPower().getValue(), blocker.getToughness().getValue())); + amounts = player.getMultiAmountWithIndividualConstraints(Outcome.Damage, damageDivision, damage, damage, dialogue, game); + } else { + amounts = new LinkedList<>(); + amounts.add(damage); + } + if (!damageDivision.isEmpty()){ + for (int i=0; i entry : assigned.entrySet()) { Permanent attacker = game.getPermanent(entry.getKey()); - attacker.markDamage(entry.getValue(), blocker.getId(), null, game, true, true); + if (attacker != null) { + attacker.markDamage(entry.getValue(), blocker.getId(), null, game, true, true); + } } } } @@ -632,74 +585,11 @@ public class CombatGroup implements Serializable, Copyable { if (blockerId != null && blocker != null) { blocker.setBlocking(blocker.getBlocking() + 1); blockers.add(blockerId); - blockerOrder.add(blockerId); this.blocked = true; this.players.put(blockerId, playerId); } } - public void pickBlockerOrder(UUID playerId, Game game) { - if (blockers.isEmpty()) { - return; - } - Player player = game.getPlayer(playerId); // game.getPlayer(defenderAssignsCombatDamage(game) ? defendingPlayerId : playerId); // this was incorrect because defenderAssignsCombatDamage might be false by the time damage is dealt - List blockerList = new ArrayList<>(blockers); - blockerOrder.clear(); - while (player.canRespond()) { - if (blockerList.size() == 1) { - blockerOrder.add(blockerList.get(0)); - break; - } else { - List blockerPerms = new ArrayList<>(); - for (UUID blockerId : blockerList) { - blockerPerms.add(game.getPermanent(blockerId)); - } - UUID blockerId = player.chooseBlockerOrder(blockerPerms, this, blockerOrder, game); - blockerOrder.add(blockerId); - blockerList.remove(blockerId); - } - } - if (!game.isSimulation() && blockerOrder.size() > 1) { - logDamageAssignmentOrder("Creatures blocking ", attackers, blockerOrder, game); - } - } - - public void pickAttackerOrder(UUID playerId, Game game) { - Player player = game.getPlayer(playerId); - if (attackers.isEmpty() || player == null) { - return; - } - List attackerList = new ArrayList<>(attackers); - List newAttackerOrder = new ArrayList<>(); - while (true) { - if (attackerList.size() == 1) { - newAttackerOrder.add(attackerList.get(0)); - break; - } else { - List attackerPerms = new ArrayList<>(); - for (UUID attackerId : attackerList) { - attackerPerms.add(game.getPermanent(attackerId)); - } - UUID attackerId = player.chooseAttackerOrder(attackerPerms, game); - if (attackerId == null) { - break; - } - newAttackerOrder.add(attackerId); - attackerList.remove(attackerId); - } - } - if (attackerOrder.isEmpty() || newAttackerOrder.size() == attackerOrder.size()) { - attackerOrder.clear(); - attackerOrder.addAll(newAttackerOrder); - - if (!game.isSimulation() && attackerOrder.size() > 1) { - logDamageAssignmentOrder("Creatures blocked by ", blockers, attackerOrder, game); - } - } else { - game.informPlayers(player.getLogName() + " try to skip choose attacker order"); - } - } - private void logDamageAssignmentOrder(String prefix, List assignedFor, List assignedOrder, Game game) { StringBuilder sb = new StringBuilder(prefix); boolean first = true; @@ -746,12 +636,9 @@ public class CombatGroup implements Serializable, Copyable { formerAttackers.add(creatureId); attackers.remove(creatureId); result = true; - attackerOrder.remove(creatureId); } else if (blockers.contains(creatureId)) { blockers.remove(creatureId); result = true; - //20100423 - 509.2a - blockerOrder.remove(creatureId); } return result; } @@ -825,7 +712,6 @@ public class CombatGroup implements Serializable, Copyable { game.getCombat().removeBlocker(blockerId, game); } blockers.clear(); - blockerOrder.clear(); if (!game.isSimulation()) { game.informPlayers(attacker.getLogName() + " can't be blocked except by " + attacker.getMinBlockedBy() + " or more creatures. Blockers discarded."); } @@ -844,7 +730,6 @@ public class CombatGroup implements Serializable, Copyable { game.getCombat().removeBlocker(blockerId, game); } blockers.clear(); - blockerOrder.clear(); if (!game.isSimulation()) { game.informPlayers(new StringBuilder(attacker.getLogName()) .append(" can't be blocked by more than ").append(attacker.getMaxBlockedBy()) diff --git a/Mage/src/main/java/mage/game/permanent/token/CrushOfTentaclesToken.java b/Mage/src/main/java/mage/game/permanent/token/CrushOfTentaclesToken.java deleted file mode 100644 index 831465f93fc..00000000000 --- a/Mage/src/main/java/mage/game/permanent/token/CrushOfTentaclesToken.java +++ /dev/null @@ -1,29 +0,0 @@ -package mage.game.permanent.token; - -import mage.MageInt; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * @author spjspj - */ -public final class CrushOfTentaclesToken extends TokenImpl { - - public CrushOfTentaclesToken() { - super("Octopus Token", "8/8 blue Octopus creature"); - this.cardType.add(CardType.CREATURE); - this.color.setBlue(true); - this.subtype.add(SubType.OCTOPUS); - this.power = new MageInt(8); - this.toughness = new MageInt(8); - } - - private CrushOfTentaclesToken(final CrushOfTentaclesToken token) { - super(token); - } - - public CrushOfTentaclesToken copy() { - return new CrushOfTentaclesToken(this); - } - -} diff --git a/Mage/src/main/java/mage/game/permanent/token/DinDragonToken.java b/Mage/src/main/java/mage/game/permanent/token/DinDragonToken.java index c833b1d4418..87cac3c1118 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DinDragonToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DinDragonToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class DinDragonToken extends TokenImpl { public DinDragonToken() { - super("Dragon Token", "4/4 red Dinosaur Dragon creature token with flying"); + super("Dinosaur Dragon Token", "4/4 red Dinosaur Dragon creature token with flying"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.DINOSAUR); diff --git a/Mage/src/main/java/mage/game/permanent/token/EyesOfTheWisentElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/Elemental44GreenToken.java similarity index 59% rename from Mage/src/main/java/mage/game/permanent/token/EyesOfTheWisentElementalToken.java rename to Mage/src/main/java/mage/game/permanent/token/Elemental44GreenToken.java index 15f41debc84..2d6ed9040f5 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EyesOfTheWisentElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/Elemental44GreenToken.java @@ -7,9 +7,9 @@ import mage.constants.SubType; /** * @author spjspj */ -public final class EyesOfTheWisentElementalToken extends TokenImpl { +public final class Elemental44GreenToken extends TokenImpl { - public EyesOfTheWisentElementalToken() { + public Elemental44GreenToken() { super("Elemental Token", "4/4 green Elemental creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); @@ -18,11 +18,11 @@ public final class EyesOfTheWisentElementalToken extends TokenImpl { toughness = new MageInt(4); } - private EyesOfTheWisentElementalToken(final EyesOfTheWisentElementalToken token) { + private Elemental44GreenToken(final Elemental44GreenToken token) { super(token); } - public EyesOfTheWisentElementalToken copy() { - return new EyesOfTheWisentElementalToken(this); + public Elemental44GreenToken copy() { + return new Elemental44GreenToken(this); } } diff --git a/Mage/src/main/java/mage/game/permanent/token/SeedGuardianToken.java b/Mage/src/main/java/mage/game/permanent/token/ElementalXXGreenToken.java similarity index 60% rename from Mage/src/main/java/mage/game/permanent/token/SeedGuardianToken.java rename to Mage/src/main/java/mage/game/permanent/token/ElementalXXGreenToken.java index f0fa5a71677..3e1cfa21e86 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SeedGuardianToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ElementalXXGreenToken.java @@ -7,13 +7,13 @@ import mage.constants.SubType; /** * @author spjspj */ -public final class SeedGuardianToken extends TokenImpl { +public final class ElementalXXGreenToken extends TokenImpl { - public SeedGuardianToken() { + public ElementalXXGreenToken() { this(1); } - public SeedGuardianToken(int xValue) { + public ElementalXXGreenToken(int xValue) { super("Elemental Token", "X/X green Elemental creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); @@ -22,11 +22,11 @@ public final class SeedGuardianToken extends TokenImpl { toughness = new MageInt(xValue); } - private SeedGuardianToken(final SeedGuardianToken token) { + private ElementalXXGreenToken(final ElementalXXGreenToken token) { super(token); } - public SeedGuardianToken copy() { - return new SeedGuardianToken(this); + public ElementalXXGreenToken copy() { + return new ElementalXXGreenToken(this); } } diff --git a/Mage/src/main/java/mage/game/permanent/token/GrovetenderDruidsPlantToken.java b/Mage/src/main/java/mage/game/permanent/token/GrovetenderDruidsPlantToken.java deleted file mode 100644 index cc98203651e..00000000000 --- a/Mage/src/main/java/mage/game/permanent/token/GrovetenderDruidsPlantToken.java +++ /dev/null @@ -1,28 +0,0 @@ -package mage.game.permanent.token; - -import mage.MageInt; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * @author spjspj - */ -public final class GrovetenderDruidsPlantToken extends TokenImpl { - - public GrovetenderDruidsPlantToken() { - super("Plant Token", "1/1 green Plant creature token"); - cardType.add(CardType.CREATURE); - color.setGreen(true); - subtype.add(SubType.PLANT); - power = new MageInt(1); - toughness = new MageInt(1); - } - - private GrovetenderDruidsPlantToken(final GrovetenderDruidsPlantToken token) { - super(token); - } - - public GrovetenderDruidsPlantToken copy() { - return new GrovetenderDruidsPlantToken(this); - } -} diff --git a/Mage/src/main/java/mage/game/permanent/token/FleshCarverHorrorToken.java b/Mage/src/main/java/mage/game/permanent/token/HorrorXXBlackToken.java similarity index 59% rename from Mage/src/main/java/mage/game/permanent/token/FleshCarverHorrorToken.java rename to Mage/src/main/java/mage/game/permanent/token/HorrorXXBlackToken.java index a91f64a5a8f..478a123e926 100644 --- a/Mage/src/main/java/mage/game/permanent/token/FleshCarverHorrorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HorrorXXBlackToken.java @@ -7,13 +7,13 @@ import mage.constants.SubType; /** * @author spjspj */ -public final class FleshCarverHorrorToken extends TokenImpl { +public final class HorrorXXBlackToken extends TokenImpl { - public FleshCarverHorrorToken() { + public HorrorXXBlackToken() { this(1); } - public FleshCarverHorrorToken(int xValue) { + public HorrorXXBlackToken(int xValue) { super("Horror Token", "X/X black Horror creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); @@ -22,11 +22,11 @@ public final class FleshCarverHorrorToken extends TokenImpl { toughness = new MageInt(xValue); } - private FleshCarverHorrorToken(final FleshCarverHorrorToken token) { + private HorrorXXBlackToken(final HorrorXXBlackToken token) { super(token); } - public FleshCarverHorrorToken copy() { - return new FleshCarverHorrorToken(this); + public HorrorXXBlackToken copy() { + return new HorrorXXBlackToken(this); } } diff --git a/Mage/src/main/java/mage/game/permanent/token/HumanRogueToken.java b/Mage/src/main/java/mage/game/permanent/token/HumanRogueToken.java index a28573e5d3c..05e3708d76e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HumanRogueToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HumanRogueToken.java @@ -10,7 +10,7 @@ import mage.constants.SubType; public final class HumanRogueToken extends TokenImpl { public HumanRogueToken() { - super("Human Token", "1/1 white Human Rogue creature token"); + super("Human Rogue Token", "1/1 white Human Rogue creature token"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.HUMAN); diff --git a/Mage/src/main/java/mage/game/permanent/token/MarathWillOfTheWildElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/MarathWillOfTheWildElementalToken.java deleted file mode 100644 index ee2ed8f36b1..00000000000 --- a/Mage/src/main/java/mage/game/permanent/token/MarathWillOfTheWildElementalToken.java +++ /dev/null @@ -1,30 +0,0 @@ - - -package mage.game.permanent.token; - -import mage.constants.CardType; -import mage.constants.SubType; -import mage.MageInt; - -/** - * @author spjspj - */ -public final class MarathWillOfTheWildElementalToken extends TokenImpl { - - public MarathWillOfTheWildElementalToken() { - super("Elemental Token", "X/X green Elemental creature token"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.ELEMENTAL); - color.setGreen(true); - power = new MageInt(0); - toughness = new MageInt(0); - } - - private MarathWillOfTheWildElementalToken(final MarathWillOfTheWildElementalToken token) { - super(token); - } - - public MarathWillOfTheWildElementalToken copy() { - return new MarathWillOfTheWildElementalToken(this); - } -} diff --git a/Mage/src/main/java/mage/game/permanent/token/MinionToken.java b/Mage/src/main/java/mage/game/permanent/token/MinionToken.java index 5b3862b9562..7d1c5f5b5ce 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MinionToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MinionToken.java @@ -5,25 +5,20 @@ import mage.constants.CardType; import mage.constants.SubType; /** - * @author FenrisulfrX + * @author Quercitron */ public final class MinionToken extends TokenImpl { public MinionToken() { - this("DDE"); - } - - public MinionToken(String setCode) { - super("Phyrexian Minion Token", "X/X black Phyrexian Minion creature token"); + super("Minion Token", "1/1 black Minion creature token"); cardType.add(CardType.CREATURE); - subtype.add(SubType.PHYREXIAN); subtype.add(SubType.MINION); color.setBlack(true); - power = new MageInt(0); - toughness = new MageInt(0); + power = new MageInt(1); + toughness = new MageInt(1); } - private MinionToken(final MinionToken token) { + protected MinionToken(final MinionToken token) { super(token); } diff --git a/Mage/src/main/java/mage/game/permanent/token/MinionToken2.java b/Mage/src/main/java/mage/game/permanent/token/MinionToken2.java deleted file mode 100644 index b35acab5e35..00000000000 --- a/Mage/src/main/java/mage/game/permanent/token/MinionToken2.java +++ /dev/null @@ -1,28 +0,0 @@ -package mage.game.permanent.token; - -import mage.MageInt; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * @author Quercitron - */ -public final class MinionToken2 extends TokenImpl { - - public MinionToken2() { - super("Minion Token", "1/1 black Minion creature token"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.MINION); - color.setBlack(true); - power = new MageInt(1); - toughness = new MageInt(1); - } - - protected MinionToken2(final MinionToken2 token) { - super(token); - } - - public MinionToken2 copy() { - return new MinionToken2(this); - } -} diff --git a/Mage/src/main/java/mage/game/permanent/token/NighteyesTheDesecratorToken.java b/Mage/src/main/java/mage/game/permanent/token/NighteyesTheDesecratorToken.java deleted file mode 100644 index dc11eaf6383..00000000000 --- a/Mage/src/main/java/mage/game/permanent/token/NighteyesTheDesecratorToken.java +++ /dev/null @@ -1,44 +0,0 @@ - - -package mage.game.permanent.token; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.Zone; -import mage.filter.StaticFilters; -import mage.target.common.TargetCardInGraveyard; - -/** - * @author spjspj - */ -public final class NighteyesTheDesecratorToken extends TokenImpl { - - public NighteyesTheDesecratorToken() { - super("Nighteyes the Desecrator Token", ""); - this.supertype.add(SuperType.LEGENDARY); - cardType.add(CardType.CREATURE); - color.setBlack(true); - subtype.add(SubType.RAT); - subtype.add(SubType.WIZARD); - power = new MageInt(4); - toughness = new MageInt(2); - // {4}{B}: Put target creature card from a graveyard onto the battlefield under your control. - Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), new ManaCostsImpl<>("{4}{B}")); - ability.addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURE_A_GRAVEYARD)); - this.addAbility(ability); - } - - private NighteyesTheDesecratorToken(final NighteyesTheDesecratorToken token) { - super(token); - } - - public NighteyesTheDesecratorToken copy() { - return new NighteyesTheDesecratorToken(this); - } -} diff --git a/Mage/src/main/java/mage/game/permanent/token/NoFlyingSpiritWhiteToken.java b/Mage/src/main/java/mage/game/permanent/token/NoFlyingSpiritWhiteToken.java new file mode 100644 index 00000000000..60e7644cc70 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/NoFlyingSpiritWhiteToken.java @@ -0,0 +1,29 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author PurpleCrowbar + */ +public final class NoFlyingSpiritWhiteToken extends TokenImpl { + + public NoFlyingSpiritWhiteToken() { + super("Spirit Token", "1/1 white Spirit creature token"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.SPIRIT); + color.setWhite(true); + power = new MageInt(1); + toughness = new MageInt(1); + } + + private NoFlyingSpiritWhiteToken(final NoFlyingSpiritWhiteToken token) { + super(token); + } + + @Override + public NoFlyingSpiritWhiteToken copy() { + return new NoFlyingSpiritWhiteToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/PhyrexianMinionToken.java b/Mage/src/main/java/mage/game/permanent/token/PhyrexianMinionToken.java new file mode 100644 index 00000000000..488d2dd80f8 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/PhyrexianMinionToken.java @@ -0,0 +1,33 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author FenrisulfrX + */ +public final class PhyrexianMinionToken extends TokenImpl { + + public PhyrexianMinionToken() { + this(1); + } + + public PhyrexianMinionToken(int xValue) { + super("Phyrexian Minion Token", "X/X black Phyrexian Minion creature token"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.PHYREXIAN); + subtype.add(SubType.MINION); + color.setBlack(true); + power = new MageInt(xValue); + toughness = new MageInt(xValue); + } + + private PhyrexianMinionToken(final PhyrexianMinionToken token) { + super(token); + } + + public PhyrexianMinionToken copy() { + return new PhyrexianMinionToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/GrismoldPlantToken.java b/Mage/src/main/java/mage/game/permanent/token/Plant11Token.java similarity index 62% rename from Mage/src/main/java/mage/game/permanent/token/GrismoldPlantToken.java rename to Mage/src/main/java/mage/game/permanent/token/Plant11Token.java index 67f3f33d09d..6967daf5c7b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GrismoldPlantToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/Plant11Token.java @@ -4,9 +4,12 @@ import mage.MageInt; import mage.constants.CardType; import mage.constants.SubType; -public final class GrismoldPlantToken extends TokenImpl { +/** + * @author spjspj + */ +public final class Plant11Token extends TokenImpl { - public GrismoldPlantToken() { + public Plant11Token() { super("Plant Token", "1/1 green Plant creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); @@ -15,11 +18,11 @@ public final class GrismoldPlantToken extends TokenImpl { toughness = new MageInt(1); } - private GrismoldPlantToken(final GrismoldPlantToken token) { + private Plant11Token(final Plant11Token token) { super(token); } - public GrismoldPlantToken copy() { - return new GrismoldPlantToken(this); + public Plant11Token copy() { + return new Plant11Token(this); } } diff --git a/Mage/src/main/java/mage/game/permanent/token/RallyTheHordeWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/RallyTheHordeWarriorToken.java deleted file mode 100644 index 6a1d3310496..00000000000 --- a/Mage/src/main/java/mage/game/permanent/token/RallyTheHordeWarriorToken.java +++ /dev/null @@ -1,29 +0,0 @@ - -package mage.game.permanent.token; - -import mage.constants.CardType; -import mage.constants.SubType; -import mage.MageInt; - -/** - * @author spjspj - */ -public final class RallyTheHordeWarriorToken extends TokenImpl { - - public RallyTheHordeWarriorToken() { - super("Warrior Token", "1/1 red Warrior creature token"); - cardType.add(CardType.CREATURE); - color.setRed(true); - subtype.add(SubType.WARRIOR); - power = new MageInt(1); - toughness = new MageInt(1); - } - - private RallyTheHordeWarriorToken(final RallyTheHordeWarriorToken token) { - super(token); - } - - public RallyTheHordeWarriorToken copy() { - return new RallyTheHordeWarriorToken(this); - } -} diff --git a/Mage/src/main/java/mage/game/permanent/token/Soldier22Token.java b/Mage/src/main/java/mage/game/permanent/token/Soldier22Token.java new file mode 100644 index 00000000000..0ddf938b3c1 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/Soldier22Token.java @@ -0,0 +1,29 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author PurpleCrowbar + */ +public final class Soldier22Token extends TokenImpl { + + public Soldier22Token() { + super("Soldier Token", "2/2 white Soldier creature token"); + cardType.add(CardType.CREATURE); + color.setWhite(true); + subtype.add(SubType.SOLDIER); + power = new MageInt(2); + toughness = new MageInt(2); + } + + private Soldier22Token(final Soldier22Token token) { + super(token); + } + + @Override + public Soldier22Token copy() { + return new Soldier22Token(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/SorinSolemnVisitorVampireToken.java b/Mage/src/main/java/mage/game/permanent/token/SorinSolemnVisitorVampireToken.java deleted file mode 100644 index 8ad1c68fe31..00000000000 --- a/Mage/src/main/java/mage/game/permanent/token/SorinSolemnVisitorVampireToken.java +++ /dev/null @@ -1,30 +0,0 @@ -package mage.game.permanent.token; - -import mage.MageInt; -import mage.abilities.keyword.FlyingAbility; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * @author spjspj - */ -public final class SorinSolemnVisitorVampireToken extends TokenImpl { - - public SorinSolemnVisitorVampireToken() { - super("Vampire Token", "2/2 black Vampire creature token with flying"); - cardType.add(CardType.CREATURE); - color.setBlack(true); - subtype.add(SubType.VAMPIRE); - power = new MageInt(2); - toughness = new MageInt(2); - addAbility(FlyingAbility.getInstance()); - } - - private SorinSolemnVisitorVampireToken(final SorinSolemnVisitorVampireToken token) { - super(token); - } - - public SorinSolemnVisitorVampireToken copy() { - return new SorinSolemnVisitorVampireToken(this); - } -} diff --git a/Mage/src/main/java/mage/game/permanent/token/SpoilsOfBloodHorrorToken.java b/Mage/src/main/java/mage/game/permanent/token/SpoilsOfBloodHorrorToken.java deleted file mode 100644 index db8966a8181..00000000000 --- a/Mage/src/main/java/mage/game/permanent/token/SpoilsOfBloodHorrorToken.java +++ /dev/null @@ -1,32 +0,0 @@ -package mage.game.permanent.token; - -import mage.MageInt; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * @author spjspj - */ -public final class SpoilsOfBloodHorrorToken extends TokenImpl { - - public SpoilsOfBloodHorrorToken() { - this(1); - } - - public SpoilsOfBloodHorrorToken(int xValue) { - super("Horror Token", "X/X black Horror creature token"); - cardType.add(CardType.CREATURE); - color.setBlack(true); - subtype.add(SubType.HORROR); - power = new MageInt(xValue); - toughness = new MageInt(xValue); - } - - private SpoilsOfBloodHorrorToken(final SpoilsOfBloodHorrorToken token) { - super(token); - } - - public SpoilsOfBloodHorrorToken copy() { - return new SpoilsOfBloodHorrorToken(this); - } -} diff --git a/Mage/src/main/java/mage/game/permanent/token/WalkerOfTheGroveToken.java b/Mage/src/main/java/mage/game/permanent/token/WalkerOfTheGroveToken.java deleted file mode 100644 index e660b616776..00000000000 --- a/Mage/src/main/java/mage/game/permanent/token/WalkerOfTheGroveToken.java +++ /dev/null @@ -1,29 +0,0 @@ -package mage.game.permanent.token; - -import mage.MageInt; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * @author spjspj - */ - -public final class WalkerOfTheGroveToken extends TokenImpl { - - public WalkerOfTheGroveToken() { - super("Elemental Token", "4/4 green Elemental creature token"); - cardType.add(CardType.CREATURE); - this.subtype.add(SubType.ELEMENTAL); - this.color.setGreen(true); - power = new MageInt(4); - toughness = new MageInt(4); - } - - private WalkerOfTheGroveToken(final WalkerOfTheGroveToken token) { - super(token); - } - - public WalkerOfTheGroveToken copy() { - return new WalkerOfTheGroveToken(this); - } -} diff --git a/Mage/src/main/java/mage/game/turn/DeclareBlockersStep.java b/Mage/src/main/java/mage/game/turn/DeclareBlockersStep.java index 0e33c98afcb..063670ed7b4 100644 --- a/Mage/src/main/java/mage/game/turn/DeclareBlockersStep.java +++ b/Mage/src/main/java/mage/game/turn/DeclareBlockersStep.java @@ -1,12 +1,12 @@ package mage.game.turn; -import java.util.UUID; - import mage.constants.PhaseStep; import mage.game.Game; import mage.game.events.GameEvent.EventType; +import java.util.UUID; + /** * @author BetaSteward_at_googlemail.com */ @@ -37,7 +37,6 @@ public class DeclareBlockersStep extends Step { game.getCombat().selectBlockers(game); if (!game.isPaused() && !game.executingRollback()) { game.getCombat().acceptBlockers(game); - game.getCombat().damageAssignmentOrder(game); } } @@ -46,7 +45,6 @@ public class DeclareBlockersStep extends Step { super.resumeBeginStep(game, activePlayerId); game.getCombat().resumeSelectBlockers(game); game.getCombat().acceptBlockers(game); - game.getCombat().damageAssignmentOrder(game); } @Override diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index 5e8286c5b6e..c6c7d14039c 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -23,7 +23,6 @@ import mage.filter.FilterCard; import mage.filter.FilterMana; import mage.filter.FilterPermanent; import mage.game.*; -import mage.game.combat.CombatGroup; import mage.game.draft.Draft; import mage.game.events.GameEvent; import mage.game.match.Match; @@ -761,19 +760,6 @@ public interface Player extends MageItem, Copyable { void selectBlockers(Ability source, Game game, UUID defendingPlayerId); - UUID chooseAttackerOrder(List attacker, Game game); - - /** - * Choose the order in which blockers get damage assigned to - * - * @param blockers list of blockers where to choose the next one from - * @param combatGroup the concerning combat group - * @param blockerOrder the already set order of blockers - * @param game - * @return blocker next to add to the blocker order - */ - UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, List blockerOrder, Game game); - int getAmount(int min, int max, String message, Game game); /** diff --git a/Mage/src/main/java/mage/players/StubPlayer.java b/Mage/src/main/java/mage/players/StubPlayer.java index d1fa0f7d57b..da4d4167d2d 100644 --- a/Mage/src/main/java/mage/players/StubPlayer.java +++ b/Mage/src/main/java/mage/players/StubPlayer.java @@ -18,10 +18,8 @@ import mage.constants.Outcome; import mage.constants.RangeOfInfluence; import mage.filter.FilterMana; import mage.game.Game; -import mage.game.combat.CombatGroup; import mage.game.draft.Draft; import mage.game.match.Match; -import mage.game.permanent.Permanent; import mage.game.tournament.Tournament; import mage.target.Target; import mage.target.TargetAmount; @@ -190,16 +188,6 @@ public class StubPlayer extends PlayerImpl { } - @Override - public UUID chooseAttackerOrder(List attacker, Game game) { - return null; - } - - @Override - public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, List blockerOrder, Game game) { - return null; - } - @Override public int getAmount(int min, int max, String message, Game game) { return 0; diff --git a/Mage/src/main/resources/tokens-database.txt b/Mage/src/main/resources/tokens-database.txt index 2064f6cd4ef..0b77e47469c 100644 --- a/Mage/src/main/resources/tokens-database.txt +++ b/Mage/src/main/resources/tokens-database.txt @@ -178,6 +178,7 @@ |Generate|DUNGEON:AFR|Tomb of Annihilation|||TombOfAnnihilationDungeon| |Generate|DUNGEON:AFR|Lost Mine of Phandelver|||LostMineOfPhandelverDungeon| |Generate|DUNGEON:AFR|Dungeon of the Mad Mage|||DungeonOfTheMadMageDungeon| +|Generate|DUNGEON:CLB|Undercity|||UndercityDungeon| # ALL TOKENS # Usage hints: @@ -209,23 +210,8 @@ |Generate|TOK:AKH|Warrior|||WarriorVigilantToken| |Generate|TOK:AKH|Wurm|||Wurm55Token| |Generate|TOK:AKH|Zombie|||ZombieToken| -#TOK:AKH - some tokens from real cards (see Embalm ability) -#|Generate|TOK:AKH|Angel of Sanctions|| -#|Generate|TOK:AKH|Anointer Priest|| -#|Generate|TOK:AKH|Aven Initiate|| -#|Generate|TOK:AKH|Aven Wind Guide|| -#|Generate|TOK:AKH|Glyph Keeper|| -#|Generate|TOK:AKH|Heart-Piercer Manticore|| -#|Generate|TOK:AKH|Honored Hydra|| -#|Generate|TOK:AKH|Labyrinth Guardian|| -#|Generate|TOK:AKH|Oketra's Attendant|| -#|Generate|TOK:AKH|Sacred Cat|| -#|Generate|TOK:AKH|Tah-Crop Skirmisher|| -#|Generate|TOK:AKH|Temmet, Vizier of Naktamun|| -#|Generate|TOK:AKH|Trueheart Duelist|| -#|Generate|TOK:AKH|Unwavering Initiate|| -#|Generate|TOK:AKH|Vizier of Many Faces|| +# ALA |Generate|TOK:ALA|Beast|||GodSireBeastToken| |Generate|TOK:ALA|Dragon|||DragonToken| |Generate|TOK:ALA|Goblin|||GoblinToken| @@ -236,28 +222,36 @@ |Generate|TOK:ALA|Soldier|||SoldierToken| |Generate|TOK:ALA|Thopter|||ThopterToken| |Generate|TOK:ALA|Zombie|||ZombieToken| + +# ARB |Generate|TOK:ARB|Bird Soldier|||BirdSoldierToken| |Generate|TOK:ARB|Dragon|||DragonBroodmotherDragonToken| |Generate|TOK:ARB|Lizard|||LizardToken| -|Generate|TOK:ARN|Djinn|||DjinnToken| +|Generate|TOK:ARB|Zombie Wizard|||ZombieWizardToken| + +# AVR |Generate|TOK:AVR|Angel|||AngelToken| |Generate|TOK:AVR|Demon|||DemonToken| -|Generate|TOK:AVR|Human|1||RedHumanToken| +|Generate|TOK:AVR|Human|1||ThatcherHumanToken| |Generate|TOK:AVR|Human|2||HumanToken| |Generate|TOK:AVR|Spirit|1||SpiritBlueToken| |Generate|TOK:AVR|Spirit|2||SpiritWhiteToken| |Generate|TOK:AVR|Zombie|||ZombieToken| + +# BFZ |Generate|TOK:BFZ|Dragon|||DragonToken2| +|Generate|TOK:BFZ|Eldrazi|||EldraziToken| |Generate|TOK:BFZ|Eldrazi Scion|1||EldraziScionToken| |Generate|TOK:BFZ|Eldrazi Scion|2||EldraziScionToken| |Generate|TOK:BFZ|Eldrazi Scion|3||EldraziScionToken| -|Generate|TOK:BFZ|Eldrazi|||EldraziToken| |Generate|TOK:BFZ|Elemental|1||OmnathElementalToken| |Generate|TOK:BFZ|Elemental|2||Elemental31TrampleHasteToken| |Generate|TOK:BFZ|Knight Ally|||KnightAllyToken| |Generate|TOK:BFZ|Kor Ally|||KorAllyToken| |Generate|TOK:BFZ|Octopus|||OctopusToken| -|Generate|TOK:BFZ|Plant|||GrovetenderDruidsPlantToken| +|Generate|TOK:BFZ|Plant|||Plant11Token| + +# BNG |Generate|TOK:BNG|Bird|1||EnchantmentBirdToken| |Generate|TOK:BNG|Bird|2||BirdToken| |Generate|TOK:BNG|Cat Soldier|||CatSoldierCreatureToken| @@ -268,6 +262,8 @@ |Generate|TOK:BNG|Soldier|||GodFavoredGeneralSoldierToken| |Generate|TOK:BNG|Wolf|||WolfToken| |Generate|TOK:BNG|Zombie|||ForlornPseudammaZombieToken| + +# C14 |Generate|TOK:C14|Angel|||AngelToken| |Generate|TOK:C14|Ape|||ApeToken| |Generate|TOK:C14|Beast|1||BeastToken| @@ -281,15 +277,17 @@ |Generate|TOK:C14|Elf Warrior|||ElfWarriorToken| |Generate|TOK:C14|Fish|||ReefWormFishToken| |Generate|TOK:C14|Gargoyle|||GargoyleToken| -|Generate|TOK:C14|Phyrexian Germ|||PhyrexianGermToken| |Generate|TOK:C14|Goat|||GoatToken| |Generate|TOK:C14|Goblin|||GoblinToken| -|Generate|TOK:C14|Horror|||SpoilsOfBloodHorrorToken| +|Generate|TOK:C14|Horror|||HorrorXXBlackToken| |Generate|TOK:C14|Kor Soldier|||KorSoldierToken| |Generate|TOK:C14|Kraken|||Kraken99Token| |Generate|TOK:C14|Myr|||MyrToken| |Generate|TOK:C14|Pegasus|||PegasusToken| |Generate|TOK:C14|Pentavite|||PentaviteToken| +|Generate|TOK:C14|Phyrexian Germ|||PhyrexianGermToken| +|Generate|TOK:C14|Phyrexian Wurm|1||WurmWithDeathtouchToken| +|Generate|TOK:C14|Phyrexian Wurm|2||WurmWithLifelinkToken| |Generate|TOK:C14|Soldier|||SoldierToken| |Generate|TOK:C14|Spirit|||SpiritWhiteToken| |Generate|TOK:C14|Stoneforged Blade|||NahiriTheLithomancerEquipmentToken| @@ -297,10 +295,10 @@ |Generate|TOK:C14|Tuktuk the Returned|||TuktukTheReturnedToken| |Generate|TOK:C14|Whale|||ReefWormWhaleToken| |Generate|TOK:C14|Wolf|||WolfToken| -|Generate|TOK:C14|Phyrexian Wurm|1||WurmWithDeathtouchToken| -|Generate|TOK:C14|Phyrexian Wurm|2||WurmWithLifelinkToken| |Generate|TOK:C14|Zombie|1||ZombieToken| |Generate|TOK:C14|Zombie|2||StitcherGeralfZombieToken| + +# C15 |Generate|TOK:C15|Angel|||AngelToken| |Generate|TOK:C15|Bear|||BearToken| |Generate|TOK:C15|Beast|||BeastToken2| @@ -311,11 +309,11 @@ |Generate|TOK:C15|Elemental Shaman|||ElementalShamanToken| |Generate|TOK:C15|Elephant|||ElephantToken| |Generate|TOK:C15|Frog Lizard|||FrogLizardToken| -|Generate|TOK:C15|Phyrexian Germ|||PhyrexianGermToken| |Generate|TOK:C15|Gold|||GoldToken| |Generate|TOK:C15|Knight|1||HuntedDragonKnightToken| |Generate|TOK:C15|Knight|2||KnightToken| |Generate|TOK:C15|Lightning Rager|||LightningRagerToken| +|Generate|TOK:C15|Phyrexian Germ|||PhyrexianGermToken| |Generate|TOK:C15|Saproling|||SaprolingToken| |Generate|TOK:C15|Shapeshifter|||CribSwapShapeshifterWhiteToken| |Generate|TOK:C15|Snake|1||SnakeToken| @@ -325,17 +323,19 @@ |Generate|TOK:C15|Spirit|2||WhiteBlackSpiritToken| |Generate|TOK:C15|Wolf|||WolfToken| |Generate|TOK:C15|Zombie|||ZombieToken| + +# C16 |Generate|TOK:C16|Beast|||BeastToken| |Generate|TOK:C16|Bird|1||SwanSongBirdToken| |Generate|TOK:C16|Bird|2||BirdToken| |Generate|TOK:C16|Elemental|||WhiteElementalToken| |Generate|TOK:C16|Elf Warrior|||ElfWarriorToken| -|Generate|TOK:C16|Phyrexian Germ|||PhyrexianGermToken| |Generate|TOK:C16|Goat|||GoatToken| |Generate|TOK:C16|Goblin|||SpyMasterGoblinToken| -|Generate|TOK:C16|Phyrexian Horror|||PhyrexianRebirthHorrorToken| |Generate|TOK:C16|Myr|||MyrToken| |Generate|TOK:C16|Ogre|||OgreToken| +|Generate|TOK:C16|Phyrexian Germ|||PhyrexianGermToken| +|Generate|TOK:C16|Phyrexian Horror|||PhyrexianRebirthHorrorToken| |Generate|TOK:C16|Saproling|1||SaprolingToken| |Generate|TOK:C16|Saproling|2||SaprolingToken| |Generate|TOK:C16|Soldier|||SoldierToken| @@ -345,6 +345,8 @@ |Generate|TOK:C16|Thopter|||ThopterToken| |Generate|TOK:C16|Worm|||BlackGreenWormToken| |Generate|TOK:C16|Zombie|||ZombieToken| + +# C17 |Generate|TOK:C17|Bat|||BatToken| |Generate|TOK:C17|Cat|||CatToken| |Generate|TOK:C17|Cat Dragon|||WasitoraCatDragonToken| @@ -356,6 +358,8 @@ |Generate|TOK:C17|Rat|||DeathtouchRatToken| |Generate|TOK:C17|Vampire|||EdgarMarkovToken| |Generate|TOK:C17|Zombie|||ZombieToken| + +# C18 |Generate|TOK:C18|Angel|||AngelToken| |Generate|TOK:C18|Beast|1||BeastToken2| |Generate|TOK:C18|Beast|2||SpawningGroundsBeastToken| @@ -381,6 +385,8 @@ |Generate|TOK:C18|Thopter|3||ThopterToken| |Generate|TOK:C18|Worm|||BlackGreenWormToken| |Generate|TOK:C18|Zombie|||ZombieToken| + +# C19 |Generate|TOK:C19|Assassin|||AssassinToken| |Generate|TOK:C19|Beast|1||BeastToken| |Generate|TOK:C19|Beast|2||BeastToken2| @@ -392,10 +398,10 @@ |Generate|TOK:C19|Egg|||AtlaPalaniToken| |Generate|TOK:C19|Eldrazi|||EldraziToken| |Generate|TOK:C19|Gargoyle|||GargoyleToken| -|Generate|TOK:C19|Phyrexian Horror|||PhyrexianRebirthHorrorToken| |Generate|TOK:C19|Human|||HumanToken| |Generate|TOK:C19|Pegasus|||PegasusToken| -|Generate|TOK:C19|Plant|||GrismoldPlantToken| +|Generate|TOK:C19|Phyrexian Horror|||PhyrexianRebirthHorrorToken| +|Generate|TOK:C19|Plant|||Plant11Token| |Generate|TOK:C19|Rhino|||RhinoToken| |Generate|TOK:C19|Saproling|||SaprolingToken| |Generate|TOK:C19|Sculpture|||DoomedArtisanToken| @@ -405,6 +411,8 @@ |Generate|TOK:C19|Wurm|||WurmToken| |Generate|TOK:C19|Zombie|1||ZombieToken| |Generate|TOK:C19|Zombie|2||ZombieToken| + +# CMA |Generate|TOK:CMA|Beast|1||BeastToken| |Generate|TOK:CMA|Beast|2||BeastToken2| |Generate|TOK:CMA|Dragon|||DragonToken2| @@ -414,9 +422,9 @@ |Generate|TOK:CMA|Elf Druid|||ElfDruidToken| |Generate|TOK:CMA|Elf Warrior|||ElfWarriorToken| |Generate|TOK:CMA|Gargoyle|||GargoyleToken| -|Generate|TOK:CMA|Phyrexian Germ|||PhyrexianGermToken| |Generate|TOK:CMA|Kithkin Soldier|||KithkinSoldierToken| |Generate|TOK:CMA|Knight|||KnightToken| +|Generate|TOK:CMA|Phyrexian Germ|||PhyrexianGermToken| |Generate|TOK:CMA|Saproling|||SaprolingToken| |Generate|TOK:CMA|Spider|||SpiderToken| |Generate|TOK:CMA|Spirit|||SpiritWhiteToken| @@ -424,6 +432,8 @@ |Generate|TOK:CMA|Wolf|1||WolfToken| |Generate|TOK:CMA|Wolf|2||WolfToken| |Generate|TOK:CMA|Zombie|||ZombieToken| + +# CN2 |Generate|TOK:CN2|Assassin|||QueenMarchesaAssassinToken| |Generate|TOK:CN2|Beast|||BeastToken| |Generate|TOK:CN2|Construct|||DarettiConstructToken| @@ -433,6 +443,8 @@ |Generate|TOK:CN2|Soldier|||SoldierToken| |Generate|TOK:CN2|Spirit|||SpiritWhiteToken| |Generate|TOK:CN2|Zombie|||ZombieToken| + +# CNS |Generate|TOK:CNS|Construct|||DarettiConstructToken| |Generate|TOK:CNS|Demon|||DemonFlyingToken| |Generate|TOK:CNS|Elephant|||ElephantToken| @@ -441,48 +453,88 @@ |Generate|TOK:CNS|Squirrel|||SquirrelToken| |Generate|TOK:CNS|Wolf|||WolfToken| |Generate|TOK:CNS|Zombie|||ZombieToken| + +# CON |Generate|TOK:CON|Angel|||AngelToken| |Generate|TOK:CON|Elemental|||ElementalTokenWithHaste| + +# DVD |Generate|TOK:DVD|Demon|||DemonFlyingToken| |Generate|TOK:DVD|Spirit|||SpiritWhiteToken| |Generate|TOK:DVD|Thrull|||BreedingPitThrullToken| + +# GVL |Generate|TOK:GVL|Bat|||BatToken| |Generate|TOK:GVL|Beast|1||BeastToken| |Generate|TOK:GVL|Beast|2||BeastToken2| |Generate|TOK:GVL|Elephant|||ElephantToken| + +# DDC |Generate|TOK:DDC|Demon|||DemonFlyingToken| |Generate|TOK:DDC|Spirit|||SpiritWhiteToken| |Generate|TOK:DDC|Thrull|||BreedingPitThrullToken| + +# DDD |Generate|TOK:DDD|Beast|1||BeastToken| |Generate|TOK:DDD|Beast|2||BeastToken2| |Generate|TOK:DDD|Elephant|||ElephantToken| + +# DDE |Generate|TOK:DDE|Hornet|||HornetToken| -|Generate|TOK:DDE|Minion|||MinionToken| +|Generate|TOK:DDE|Phyrexian Minion|||PhyrexianMinionToken| |Generate|TOK:DDE|Saproling|||SaprolingToken| + +# DDF |Generate|TOK:DDF|Soldier|||SoldierToken| + +# DDG |Generate|TOK:DDG|Goblin|||GoblinToken| + +# DDH |Generate|TOK:DDH|Griffin|||GriffinToken| |Generate|TOK:DDH|Saproling|||SaprolingToken| + +# DDJ |Generate|TOK:DDJ|Saproling|||SaprolingToken| + +# DDK |Generate|TOK:DDK|Spirit|||SpiritWhiteToken| + +# DDL |Generate|TOK:DDL|Beast|||BeastToken| |Generate|TOK:DDL|Griffin|||GriffinToken| + +# DDM |Generate|TOK:DDM|Assassin|||AssassinToken| + +# DDN |Generate|TOK:DDN|Goblin|||GoblinToken| + +# DDO |Generate|TOK:DDO|Kraken|||Kraken99Token| |Generate|TOK:DDO|Soldier|||SoldierToken| + +# DDP |Generate|TOK:DDP|Eldrazi Spawn|1||EldraziSpawnToken| |Generate|TOK:DDP|Eldrazi Spawn|2||EldraziSpawnToken| |Generate|TOK:DDP|Eldrazi Spawn|3||EldraziSpawnToken| |Generate|TOK:DDP|Hellion|||HellionToken| |Generate|TOK:DDP|Plant|||PlantToken| + +# DDQ |Generate|TOK:DDQ|Angel|||AngelToken| |Generate|TOK:DDQ|Human|||HumanToken| |Generate|TOK:DDQ|Spirit|||SpiritWhiteToken| |Generate|TOK:DDQ|Zombie|||ZombieToken| + +# DGM |Generate|TOK:DGM|Elemental|||VoiceOfResurgenceToken| + +# DKA |Generate|TOK:DKA|Human|||HumanToken| |Generate|TOK:DKA|Vampire|||SorinLordOfInnistradVampireToken| + +# DOM |Generate|TOK:DOM|Cleric|||BelzenlokClericToken| |Generate|TOK:DOM|Construct|||KarnConstructToken| |Generate|TOK:DOM|Demon|||BelzenlokDemonToken| @@ -497,25 +549,33 @@ |Generate|TOK:DOM|Saproling|3||SaprolingToken| |Generate|TOK:DOM|Soldier|||SoldierToken| |Generate|TOK:DOM|Zombie Knight|||ZombieKnightToken| + +# DTK |Generate|TOK:DTK|Djinn Monk|||DjinnMonkToken| |Generate|TOK:DTK|Dragon|||DragonToken| |Generate|TOK:DTK|Goblin|||GoblinToken| |Generate|TOK:DTK|Warrior|||WarriorToken| -|Generate|TOK:DTK|Zombie Horror|||CorpseweftZombieToken| |Generate|TOK:DTK|Zombie|||ZombieToken| +|Generate|TOK:DTK|Zombie Horror|||CorpseweftZombieToken| + +# E01 |Generate|TOK:E01|Beast|1||BeastToken| |Generate|TOK:E01|Beast|2||BeastToken2| |Generate|TOK:E01|Soldier|||SoldierToken| |Generate|TOK:E01|Spirit|||SpiritWhiteToken| + +# E02 |Generate|TOK:E02|Saproling|||SaprolingToken| + +# EMA |Generate|TOK:EMA|Carnivore|||CarnivoreToken| |Generate|TOK:EMA|Dragon|||DragonEggDragonToken| |Generate|TOK:EMA|Elemental|1||RedElementalToken| |Generate|TOK:EMA|Elemental|2||CallTheSkyBreakerElementalToken| |Generate|TOK:EMA|Elephant|||ElephantToken| |Generate|TOK:EMA|Elf Warrior|||ElfWarriorToken| -|Generate|TOK:EMA|Goblin Soldier|||GoblinSoldierToken| |Generate|TOK:EMA|Goblin|||GoblinToken| +|Generate|TOK:EMA|Goblin Soldier|||GoblinSoldierToken| |Generate|TOK:EMA|Serf|||SerfToken| |Generate|TOK:EMA|Soldier|||SoldierToken| |Generate|TOK:EMA|Spirit|1||SpiritToken| @@ -523,20 +583,24 @@ |Generate|TOK:EMA|Wall|||TidalWaveWallToken| |Generate|TOK:EMA|Wurm|||WurmToken| |Generate|TOK:EMA|Zombie|||ZombieToken| + +# EMN +|Generate|TOK:EMN|Eldrazi Horror|||EldraziHorrorToken| +|Generate|TOK:EMN|Human|||RedHumanToken| +|Generate|TOK:EMN|Human Wizard|||HumanWizardToken| +|Generate|TOK:EMN|Spider|||SpiderToken| +|Generate|TOK:EMN|Zombie|1||ZombieToken| +|Generate|TOK:EMN|Zombie|2||ZombieToken| +|Generate|TOK:EMN|Zombie|3||ZombieToken| +|Generate|TOK:EMN|Zombie|4||ZombieToken2| #TOK:EMN - Human Soldier, Spirit, Devil, Insect and Wolf tokens from SOI set #|Generate|TOK:EMN|Devil|||DevilToken| #|Generate|TOK:EMN|Human Soldier|||HumanSoldierToken| #|Generate|TOK:EMN|Insect|||InsectToken| #|Generate|TOK:EMN|Spirit|||SpiritWhiteToken| #|Generate|TOK:EMN|Wolf|||WolfToken| -|Generate|TOK:EMN|Eldrazi Horror|||EldraziHorrorToken| -|Generate|TOK:EMN|Human Wizard|||HumanWizardToken| -|Generate|TOK:EMN|Human|||RedHumanToken| -|Generate|TOK:EMN|Spider|||SpiderToken| -|Generate|TOK:EMN|Zombie|1||ZombieToken| -|Generate|TOK:EMN|Zombie|2||ZombieToken| -|Generate|TOK:EMN|Zombie|3||ZombieToken| -|Generate|TOK:EMN|Zombie|4||ZombieToken2| + +# EVE |Generate|TOK:EVE|Beast|||BeastToken| |Generate|TOK:EVE|Bird|||BlueBirdToken| |Generate|TOK:EVE|Elemental|||CallTheSkyBreakerElementalToken| @@ -544,12 +608,18 @@ |Generate|TOK:EVE|Goblin Soldier|||GoblinSoldierToken| |Generate|TOK:EVE|Spirit|||WhiteBlackSpiritToken| |Generate|TOK:EVE|Worm|||BlackGreenWormToken| + +# EVG |Generate|TOK:EVG|Elemental|||VoiceOfTheWoodsElementalToken| |Generate|TOK:EVG|Elf Warrior|||ElfWarriorToken| |Generate|TOK:EVG|Goblin|||GoblinToken| + +# FRF |Generate|TOK:FRF|Monk|||MonasteryMentorToken| |Generate|TOK:FRF|Spirit|||SpiritWhiteToken| |Generate|TOK:FRF|Warrior|||MarduStrikeLeaderWarriorToken| + +# GTC |Generate|TOK:GTC|Angel|||AngelToken| |Generate|TOK:GTC|Cleric|||DeathpactAngelToken| |Generate|TOK:GTC|Frog Lizard|||FrogLizardToken| @@ -557,21 +627,16 @@ |Generate|TOK:GTC|Rat|||RatToken| |Generate|TOK:GTC|Soldier|||SoldierTokenWithHaste| |Generate|TOK:GTC|Spirit|||WhiteBlackSpiritToken| + +# H17 |Generate|TOK:H17|Dragon|||DragonTokenGold| + +# HOU |Generate|TOK:HOU|Horse|||CrestedSunmareToken| |Generate|TOK:HOU|Insect|||TheLocustGodInsectToken| |Generate|TOK:HOU|Snake|||RhonassLastStandToken| -#TOK:HOU - some tokens from real cards (see Eternalize ability) -#TOK:HOU - Cat, Warrior and Zombie tokens from AKH set -#|Generate|TOK:HOU|Adorned Pouncer|||| -#|Generate|TOK:HOU|Champion of Wits|||| -#|Generate|TOK:HOU|Dreamstealer|||| -#|Generate|TOK:HOU|Earthshaker Khenra|||| -#|Generate|TOK:HOU|Proven Combatant|||| -#|Generate|TOK:HOU|Resilient Khenra|||| -#|Generate|TOK:HOU|Sinuous Striker|||| -#|Generate|TOK:HOU|Steadfast Sentinel|||| -#|Generate|TOK:HOU|Sunscourge Champion|||| + +# ISD |Generate|TOK:ISD|Angel|||AngelToken| |Generate|TOK:ISD|Demon|||DemonToken| |Generate|TOK:ISD|Homunculus|||StitchersApprenticeHomunculusToken| @@ -584,12 +649,16 @@ |Generate|TOK:ISD|Zombie|1||ZombieToken| |Generate|TOK:ISD|Zombie|2||ZombieToken| |Generate|TOK:ISD|Zombie|3||ZombieToken| + +# JOU |Generate|TOK:JOU|Hydra|||HydraBroodmasterToken| |Generate|TOK:JOU|Minotaur|||MinotaurToken| |Generate|TOK:JOU|Snake|||PharikaSnakeToken| |Generate|TOK:JOU|Sphinx|||HourOfNeedSphinxToken| |Generate|TOK:JOU|Spider|||RenownedWeaverSpiderToken| |Generate|TOK:JOU|Zombie|||RitualOfTheReturnedZombieToken| + +# KLD |Generate|TOK:KLD|Beast|||ArchitectOfTheUntamedBeastToken| |Generate|TOK:KLD|Construct|1||OviyaPashiriSageLifecrafterToken| |Generate|TOK:KLD|Construct|2||MetallurgicSummoningsConstructToken| @@ -599,20 +668,23 @@ |Generate|TOK:KLD|Thopter|1||ThopterColorlessToken| |Generate|TOK:KLD|Thopter|2||ThopterColorlessToken| |Generate|TOK:KLD|Thopter|3||ThopterColorlessToken| + +# KTK |Generate|TOK:KTK|Bear|||BearsCompanionBearToken| |Generate|TOK:KTK|Bird|||WingmateRocToken| |Generate|TOK:KTK|Goblin|||GoblinToken| |Generate|TOK:KTK|Snake|||SnakeToken| -|Generate|TOK:KTK|Spirit Warrior|||SpiritWarriorToken| |Generate|TOK:KTK|Spirit|||SpiritWhiteToken| +|Generate|TOK:KTK|Spirit Warrior|||SpiritWarriorToken| |Generate|TOK:KTK|Vampire|||VampireToken| |Generate|TOK:KTK|Warrior|1||WarriorToken| |Generate|TOK:KTK|Warrior|2||WarriorToken| |Generate|TOK:KTK|Zombie|||ZombieToken| -# LGN don't have tokens, from wiki: A Sliver token for Brood Sliver and a Goblin token for Warbreak Trumpeter were featured as a Magic Player Reward. + +# LRW |Generate|TOK:LRW|Avatar|||AvatarToken| |Generate|TOK:LRW|Beast|||BeastToken| -|Generate|TOK:LRW|Elemental|1||WalkerOfTheGroveToken| +|Generate|TOK:LRW|Elemental|1||Elemental44GreenToken| |Generate|TOK:LRW|Elemental|2||WhiteElementalToken| |Generate|TOK:LRW|Elemental Shaman|||ElementalShamanToken| |Generate|TOK:LRW|Elf Warrior|||ElfWarriorToken| @@ -621,6 +693,8 @@ |Generate|TOK:LRW|Merfolk Wizard|||MerfolkWizardToken| |Generate|TOK:LRW|Shapeshifter|||CribSwapShapeshifterWhiteToken| |Generate|TOK:LRW|Wolf|||WolfToken| + +# M10 |Generate|TOK:M10|Avatar|||AvatarToken| |Generate|TOK:M10|Beast|||BeastToken| |Generate|TOK:M10|Gargoyle|||GargoyleToken| @@ -629,12 +703,16 @@ |Generate|TOK:M10|Soldier|||SoldierToken| |Generate|TOK:M10|Wolf|||WolfToken| |Generate|TOK:M10|Zombie|||ZombieToken| + +# M11 |Generate|TOK:M11|Avatar|||AvatarToken| |Generate|TOK:M11|Beast|||BeastToken| |Generate|TOK:M11|Bird|||RocEggToken| |Generate|TOK:M11|Ooze|1||MitoticSlimeOozeToken| |Generate|TOK:M11|Ooze|2||OozeToken| |Generate|TOK:M11|Zombie|||ZombieToken| + +# M12 |Generate|TOK:M12|Beast|||BeastToken| |Generate|TOK:M12|Bird|||RocEggToken| |Generate|TOK:M12|Pentavite|||PentaviteToken| @@ -642,6 +720,8 @@ |Generate|TOK:M12|Soldier|||SoldierToken| |Generate|TOK:M12|Wurm|||WurmToken| |Generate|TOK:M12|Zombie|||ZombieToken| + +# M13 |Generate|TOK:M13|Beast|||BeastToken| |Generate|TOK:M13|Cat|||CatToken| |Generate|TOK:M13|Drake|||DrakeToken| @@ -652,6 +732,8 @@ |Generate|TOK:M13|Soldier|||SoldierToken| |Generate|TOK:M13|Wurm|||WurmToken| |Generate|TOK:M13|Zombie|||ZombieToken| + +# M14 |Generate|TOK:M14|Angel|||AngelToken| |Generate|TOK:M14|Beast|||BeastToken| |Generate|TOK:M14|Cat|||CatToken| @@ -663,6 +745,8 @@ |Generate|TOK:M14|Sliver|||SliverToken| |Generate|TOK:M14|Wolf|||WolfToken| |Generate|TOK:M14|Zombie|||ZombieToken| + +# M15 |Generate|TOK:M15|Beast|1||GarrukApexPredatorBeastToken| |Generate|TOK:M15|Beast|2||BeastToken| |Generate|TOK:M15|Dragon|||DragonEggDragonToken| @@ -675,26 +759,32 @@ |Generate|TOK:M15|Squid|||SquidToken| |Generate|TOK:M15|Treefolk Warrior|||KalonianTwingroveTreefolkWarriorToken| |Generate|TOK:M15|Zombie|||ZombieToken| -|Generate|TOK:MBS|Phyrexian Germ|||PhyrexianGermToken| + +# MBS |Generate|TOK:MBS|Golem|||TitanForgeGolemToken| +|Generate|TOK:MBS|Phyrexian Germ|||PhyrexianGermToken| |Generate|TOK:MBS|Phyrexian Horror|||PhyrexianRebirthHorrorToken| |Generate|TOK:MBS|Thopter|||ThopterColorlessToken| |Generate|TOK:MBS|Zombie|||ZombieToken| + +# MED |Generate|TOK:MED|Beast|||GarrukApexPredatorBeastToken| |Generate|TOK:MED|Construct|1||KarnConstructToken| |Generate|TOK:MED|Construct|2||DarettiConstructToken| |Generate|TOK:MED|Dragon|||DragonToken| |Generate|TOK:MED|Soldier|||SoldierToken| |Generate|TOK:MED|Zombie|||ZombieToken| + +# MM2 |Generate|TOK:MM2|Eldrazi Spawn|1||EldraziSpawnToken| |Generate|TOK:MM2|Eldrazi Spawn|2||EldraziSpawnToken| |Generate|TOK:MM2|Eldrazi Spawn|3||EldraziSpawnToken| |Generate|TOK:MM2|Elephant|||ElephantToken| |Generate|TOK:MM2|Faerie Rogue|||FaerieRogueToken| -|Generate|TOK:MM2|Phyrexian Germ|||PhyrexianGermToken| |Generate|TOK:MM2|Golem|||GolemToken| |Generate|TOK:MM2|Insect|||InsectToken| |Generate|TOK:MM2|Myr|||MyrToken| +|Generate|TOK:MM2|Phyrexian Germ|||PhyrexianGermToken| |Generate|TOK:MM2|Saproling|||SaprolingToken| |Generate|TOK:MM2|Snake|||SnakeToken| |Generate|TOK:MM2|Soldier|||SoldierToken| @@ -702,6 +792,8 @@ |Generate|TOK:MM2|Thrull|||ThrullToken| |Generate|TOK:MM2|Wolf|||WolfToken| |Generate|TOK:MM2|Worm|||BlackGreenWormToken| + +# MM3 |Generate|TOK:MM3|Angel|||AngelToken| |Generate|TOK:MM3|Beast|1||BeastToken| |Generate|TOK:MM3|Beast|2||BeastToken2| @@ -713,8 +805,8 @@ |Generate|TOK:MM3|Giant Warrior|||GiantBaitingGiantWarriorToken| |Generate|TOK:MM3|Goblin|||GoblinToken| |Generate|TOK:MM3|Goblin Warrior|||GoblinWarriorToken| -|Generate|TOK:MM3|Phyrexian Golem|||PhyrexianGolemToken| |Generate|TOK:MM3|Ooze|||OozeToken| +|Generate|TOK:MM3|Phyrexian Golem|||PhyrexianGolemToken| |Generate|TOK:MM3|Saproling|||SaprolingToken| |Generate|TOK:MM3|Soldier|1||SoldierToken| |Generate|TOK:MM3|Soldier|2||SoldierTokenWithHaste| @@ -722,13 +814,15 @@ |Generate|TOK:MM3|Spirit|||SpiritWhiteToken| |Generate|TOK:MM3|Wurm|||WurmWithTrampleToken| |Generate|TOK:MM3|Zombie|||ZombieToken| + +# MMA |Generate|TOK:MMA|Bat|||BatToken| |Generate|TOK:MMA|Dragon|||DragonToken| -|Generate|TOK:MMA|Elemental|||WalkerOfTheGroveToken| +|Generate|TOK:MMA|Elemental|||Elemental44GreenToken| |Generate|TOK:MMA|Faerie Rogue|||OonaQueenFaerieRogueToken| |Generate|TOK:MMA|Giant Warrior|||GiantWarriorToken| -|Generate|TOK:MMA|Goblin Rogue|||GoblinRogueToken| |Generate|TOK:MMA|Goblin|||GoblinToken| +|Generate|TOK:MMA|Goblin Rogue|||GoblinRogueToken| |Generate|TOK:MMA|Illusion|||MelokuTheCloudedMirrorToken| |Generate|TOK:MMA|Kithkin Soldier|||KithkinSoldierToken| |Generate|TOK:MMA|Saproling|||SaprolingToken| @@ -737,19 +831,27 @@ |Generate|TOK:MMA|Treefolk Shaman|||TreefolkShamanToken| |Generate|TOK:MMA|Worm|||BlackGreenWormToken| |Generate|TOK:MMA|Zombie|||ZombieToken| + +# MOR |Generate|TOK:MOR|Faerie Rogue|||FaerieRogueToken| |Generate|TOK:MOR|Giant Warrior|||GiantWarriorToken| |Generate|TOK:MOR|Treefolk Shaman|||TreefolkShamanToken| + +# NPH |Generate|TOK:NPH|Beast|||BeastToken| |Generate|TOK:NPH|Phyrexian Goblin|||PhyrexianGoblinHasteToken| |Generate|TOK:NPH|Phyrexian Golem|||PhyrexianGolemToken| |Generate|TOK:NPH|Phyrexian Myr|||PhyrexianMyrToken| + +# ODY |Generate|TOK:ODY|Bear|||BearToken| |Generate|TOK:ODY|Beast|||BeastToken2| |Generate|TOK:ODY|Elephant|||ElephantToken| |Generate|TOK:ODY|Squirrel|||SquirrelToken| |Generate|TOK:ODY|Wurm|||WurmToken| |Generate|TOK:ODY|Zombie|||ZombieToken| + +# OGW |Generate|TOK:OGW|Angel|||Angel33Token| |Generate|TOK:OGW|Eldrazi Scion|1||EldraziScionToken| |Generate|TOK:OGW|Eldrazi Scion|2||EldraziScionToken| @@ -757,10 +859,12 @@ |Generate|TOK:OGW|Eldrazi Scion|4||EldraziScionToken| |Generate|TOK:OGW|Eldrazi Scion|5||EldraziScionToken| |Generate|TOK:OGW|Eldrazi Scion|6||EldraziScionToken| -|Generate|TOK:OGW|Elemental|1||SeedGuardianToken| +|Generate|TOK:OGW|Elemental|1||ElementalXXGreenToken| |Generate|TOK:OGW|Elemental|2||ElementalTokenWithHaste| |Generate|TOK:OGW|Plant|||PlantToken| |Generate|TOK:OGW|Zombie|||ZombieToken| + +# ORI |Generate|TOK:ORI|Angel|||AngelToken| |Generate|TOK:ORI|Ashaya, the Awoken World|||NissaSageAnimistToken| |Generate|TOK:ORI|Demon|||DemonToken| @@ -772,10 +876,14 @@ |Generate|TOK:ORI|Thopter|1||ThopterColorlessToken| |Generate|TOK:ORI|Thopter|2||ThopterColorlessToken| |Generate|TOK:ORI|Zombie|||ZombieToken| + +# RIX |Generate|TOK:RIX|Elemental|1||RekindlingPhoenixToken| |Generate|TOK:RIX|Elemental|2||RedElementalToken| |Generate|TOK:RIX|Golem|||GoldForgeGarrisonGolemToken| |Generate|TOK:RIX|Saproling|||SaprolingToken| + +# ROE |Generate|TOK:ROE|Eldrazi Spawn|1||EldraziSpawnToken| |Generate|TOK:ROE|Eldrazi Spawn|2||EldraziSpawnToken| |Generate|TOK:ROE|Eldrazi Spawn|3||EldraziSpawnToken| @@ -783,6 +891,8 @@ |Generate|TOK:ROE|Hellion|||HellionToken| |Generate|TOK:ROE|Ooze|||OozeToken| |Generate|TOK:ROE|Tuktuk the Returned|||TuktukTheReturnedToken| + +# RTR |Generate|TOK:RTR|Assassin|||AssassinToken| |Generate|TOK:RTR|Bird|||BirdToken| |Generate|TOK:RTR|Centaur|||CentaurToken| @@ -795,6 +905,8 @@ |Generate|TOK:RTR|Saproling|||SaprolingToken| |Generate|TOK:RTR|Soldier|||SoldierToken| |Generate|TOK:RTR|Wurm|||WurmWithTrampleToken| + +# SHM |Generate|TOK:SHM|Elemental|1||DinOfTheFireherdToken| |Generate|TOK:SHM|Elemental|2||Elemental11HasteToken| |Generate|TOK:SHM|Elf Warrior|1||ElfWarriorToken| @@ -807,6 +919,8 @@ |Generate|TOK:SHM|Spider|||SpiderToken| |Generate|TOK:SHM|Spirit|||SpiritWhiteToken| |Generate|TOK:SHM|Wolf|||WolfToken| + +# SOI |Generate|TOK:SOI|Angel|||AngelToken| |Generate|TOK:SOI|Clue|1||ClueArtifactToken| |Generate|TOK:SOI|Clue|2||ClueArtifactToken| @@ -823,25 +937,31 @@ |Generate|TOK:SOI|Vampire Knight|||VampireKnightToken| |Generate|TOK:SOI|Wolf|||WolfToken| |Generate|TOK:SOI|Zombie|||ZombieToken| + +# SOM |Generate|TOK:SOM|Cat|||CatToken| |Generate|TOK:SOM|Goblin|||GoblinToken| |Generate|TOK:SOM|Golem|||GolemToken| -|Generate|TOK:SOM|Phyrexian Insect|||InsectInfectToken| |Generate|TOK:SOM|Myr|||MyrToken| -|Generate|TOK:SOM|Soldier|||SoldierToken| -|Generate|TOK:SOM|Wolf|||WolfToken| +|Generate|TOK:SOM|Phyrexian Insect|||InsectInfectToken| |Generate|TOK:SOM|Phyrexian Wurm|1||WurmWithDeathtouchToken| |Generate|TOK:SOM|Phyrexian Wurm|2||WurmWithLifelinkToken| -|Generate|TOK:SWS|Ewok|||EwokToken| -|Generate|TOK:SWS|B-Wing|||RebelStarshipToken| -|Generate|TOK:SWS|Hunter|||HunterToken| -|Generate|TOK:SWS|TIE Fighter|||TIEFighterToken| -|Generate|TOK:SWS|Trooper|||TrooperToken| +|Generate|TOK:SOM|Soldier|||SoldierToken| +|Generate|TOK:SOM|Wolf|||WolfToken| + +# SWS |Generate|TOK:SWS|AT-AT|||ATATToken| +|Generate|TOK:SWS|B-Wing|||RebelStarshipToken| +|Generate|TOK:SWS|Droid|||DroidToken| +|Generate|TOK:SWS|Ewok|||EwokToken| +|Generate|TOK:SWS|Hunter|||HunterToken| |Generate|TOK:SWS|Rebel|||RebelToken| |Generate|TOK:SWS|Royal Guard|||RoyalGuardToken| +|Generate|TOK:SWS|TIE Fighter|||TIEFighterToken| +|Generate|TOK:SWS|Trooper|||TrooperToken| |Generate|TOK:SWS|Tusken Raider|||TuskenRaiderToken| -|Generate|TOK:SWS|Droid|||DroidToken| + +# THS |Generate|TOK:THS|Bird|||SwanSongBirdToken| |Generate|TOK:THS|Boar|||Boar2Token| |Generate|TOK:THS|Cleric|||HeliodGodOfTheSunToken| @@ -852,14 +972,35 @@ |Generate|TOK:THS|Soldier|1||SoldierToken| |Generate|TOK:THS|Soldier|2||SoldierToken| |Generate|TOK:THS|Soldier|3||AkroanSoldierToken| + +# UST +|Generate|TOK:UST|Angel|||AngelToken| +|Generate|TOK:UST|Beast|||BeastToken| +|Generate|TOK:UST|Brainiac|||BrainiacToken| +|Generate|TOK:UST|Clue|||ClueToken| |Generate|TOK:UST|Dragon|||DragonTokenGold| +|Generate|TOK:UST|Elemental|1||RedElementalToken| +|Generate|TOK:UST|Elemental|2||VoiceOfResurgenceToken| +|Generate|TOK:UST|Gnome|||GnomeToken| +|Generate|TOK:UST|Goat|||GoatToken| +|Generate|TOK:UST|Goblin|||GoblinToken| +|Generate|TOK:UST|Saproling|||SaprolingToken| +|Generate|TOK:UST|Spirit|||SpiritWhiteToken| +|Generate|TOK:UST|Squirrel|||SquirrelToken| |Generate|TOK:UST|Storm Crow|||StormCrowToken| +|Generate|TOK:UST|Thopter|||ThopterToken| +|Generate|TOK:UST|Vampire|||VampireToken| +|Generate|TOK:UST|Zombie|||ZombieToken| + +# WWK |Generate|TOK:WWK|Construct|||StoneIdolToken| |Generate|TOK:WWK|Dragon|||DragonToken2| |Generate|TOK:WWK|Elephant|||ElephantToken| |Generate|TOK:WWK|Ogre|||OgreToken| |Generate|TOK:WWK|Plant|||PlantToken| |Generate|TOK:WWK|Soldier Ally|||JoinTheRanksSoldierToken| + +# XLN |Generate|TOK:XLN|Dinosaur|||DinosaurToken| |Generate|TOK:XLN|Illusion|||JaceCunningCastawayIllusionToken| |Generate|TOK:XLN|Merfolk|||MerfolkHexproofToken| @@ -870,6 +1011,8 @@ |Generate|TOK:XLN|Treasure|3||TreasureToken| |Generate|TOK:XLN|Treasure|4||TreasureToken| |Generate|TOK:XLN|Vampire|||IxalanVampireToken| + +# ZEN |Generate|TOK:ZEN|Angel|||AngelToken| |Generate|TOK:ZEN|Beast|||BeastToken2| |Generate|TOK:ZEN|Bird|||BirdToken| @@ -881,6 +1024,8 @@ |Generate|TOK:ZEN|Vampire|||KalitasVampireToken| |Generate|TOK:ZEN|Wolf|||WolfToken| |Generate|TOK:ZEN|Zombie Giant|||QuestForTheGravelordZombieToken| + +# RNA |Generate|TOK:RNA|Beast|||RedGreenBeastToken| |Generate|TOK:RNA|Centaur|||CentaurToken| |Generate|TOK:RNA|Frog Lizard|||FrogLizardToken| @@ -893,12 +1038,16 @@ |Generate|TOK:RNA|Thopter|||ThopterColorlessToken| |Generate|TOK:RNA|Treasure|||TreasureToken| |Generate|TOK:RNA|Zombie|||ZombieToken| + +# GRN |Generate|TOK:GRN|Angel|||AngelVigilanceToken| |Generate|TOK:GRN|Bird Illusion|||BirdIllusionToken| |Generate|TOK:GRN|Elf Knight|||ElfKnightToken| |Generate|TOK:GRN|Goblin|||GoblinToken| |Generate|TOK:GRN|Insect|||IzoniInsectToken| |Generate|TOK:GRN|Soldier|||SoldierLifelinkToken| + +# WAR |Generate|TOK:WAR|Angel|||AngelVigilanceToken| |Generate|TOK:WAR|Assassin|||AssassinToken2| |Generate|TOK:WAR|Citizen|||PlanewideCelebrationToken| @@ -913,11 +1062,12 @@ |Generate|TOK:WAR|Wizard|||WizardToken| |Generate|TOK:WAR|Wolf|||WolfToken| |Generate|TOK:WAR|Zombie|||ZombieToken| -|Generate|TOK:WAR|Zombie Warrior|||GodEternalOketraToken| |Generate|TOK:WAR|Zombie Army|1||ZombieArmyToken| |Generate|TOK:WAR|Zombie Army|2||ZombieArmyToken| |Generate|TOK:WAR|Zombie Army|3||ZombieArmyToken| -|Generate|TOK:MH1|Shapeshifter|||ShapeshifterToken| +|Generate|TOK:WAR|Zombie Warrior|||GodEternalOketraToken| + +# MH1 |Generate|TOK:MH1|Angel|||AngelVigilanceToken| |Generate|TOK:MH1|Bear|||BearToken| |Generate|TOK:MH1|Bird|||BirdToken| @@ -931,11 +1081,14 @@ |Generate|TOK:MH1|Marit Lage|||MaritLageToken| |Generate|TOK:MH1|Myr|||MyrToken| |Generate|TOK:MH1|Rhino|||RhinoToken| +|Generate|TOK:MH1|Shapeshifter|||ShapeshifterToken| |Generate|TOK:MH1|Soldier|||SoldierToken| |Generate|TOK:MH1|Spider|||SpiderToken| |Generate|TOK:MH1|Spirit|||WhiteBlackSpiritToken| |Generate|TOK:MH1|Squirrel|||SquirrelToken| |Generate|TOK:MH1|Zombie|||ZombieToken| + +# M19 |Generate|TOK:M19|Angel|||AngelVigilanceToken| |Generate|TOK:M19|Avatar|||AvatarToken2| |Generate|TOK:M19|Bat|||BatToken| @@ -950,6 +1103,8 @@ |Generate|TOK:M19|Soldier|||SoldierToken| |Generate|TOK:M19|Thopter|||ThopterColorlessToken| |Generate|TOK:M19|Zombie|||ZombieToken| + +# M20 |Generate|TOK:M20|Ajani's Pridemate|||AjanisPridemateToken| |Generate|TOK:M20|Demon|||DemonToken| |Generate|TOK:M20|Elemental|||RedElementalToken| @@ -982,27 +1137,27 @@ |Generate|TOK:ELD|Wolf|||GarrukCursedHuntsmanToken| # THB -|Generate|TOK:THB|Goat|||GoatToken| -|Generate|TOK:THB|Human Soldier|||HumanSoldierToken| -|Generate|TOK:THB|Pegasus|||PegasusToken2| -|Generate|TOK:THB|Kraken|||KrakenHexproofToken| -|Generate|TOK:THB|Reflection|||ReflectionBlueToken| -|Generate|TOK:THB|Tentacle|||TentacleToken| -|Generate|TOK:THB|Zombie|||ZombieToken| |Generate|TOK:THB|Elemental|||PurphorossInterventionToken| +|Generate|TOK:THB|Goat|||GoatToken| +|Generate|TOK:THB|Gold|||GoldToken| +|Generate|TOK:THB|Human Soldier|||HumanSoldierToken| +|Generate|TOK:THB|Kraken|||KrakenHexproofToken| +|Generate|TOK:THB|Nightmare|||AshiokNightmareMuseToken| +|Generate|TOK:THB|Pegasus|||PegasusToken2| +|Generate|TOK:THB|Reflection|||ReflectionBlueToken| |Generate|TOK:THB|Satyr|||SatyrCantBlockToken| |Generate|TOK:THB|Spider|||SpiderToken| -|Generate|TOK:THB|Wolf|||WolfToken| -|Generate|TOK:THB|Nightmare|||AshiokNightmareMuseToken| -|Generate|TOK:THB|Gold|||GoldToken| +|Generate|TOK:THB|Tentacle|||TentacleToken| |Generate|TOK:THB|Wall|||ArtifactWallToken| +|Generate|TOK:THB|Wolf|||WolfToken| +|Generate|TOK:THB|Zombie|||ZombieToken| # IKO |Generate|TOK:IKO|Beast|||BeastToken| -|Generate|TOK:IKO|Cat Bird|||CatBirdToken| |Generate|TOK:IKO|Cat|||CatToken2| -|Generate|TOK:IKO|Dinosaur Beast|||DinosaurBeastToken| +|Generate|TOK:IKO|Cat Bird|||CatBirdToken| |Generate|TOK:IKO|Dinosaur|||DinosaurHasteToken| +|Generate|TOK:IKO|Dinosaur Beast|||DinosaurBeastToken| |Generate|TOK:IKO|Feather|||FeatherToken| |Generate|TOK:IKO|Human Soldier|1||HumanSoldierToken| |Generate|TOK:IKO|Human Soldier|2||HumanSoldierToken| @@ -1055,8 +1210,8 @@ |Generate|TOK:ZNR|Cat|||CatToken3| |Generate|TOK:ZNR|Cat Beast|||CatBeastToken| |Generate|TOK:ZNR|Construct|||ConstructToken| -|Generate|TOK:ZNR|Goblin Construct|||RelicRobberToken| |Generate|TOK:ZNR|Drake|||DrakeToken| +|Generate|TOK:ZNR|Goblin Construct|||RelicRobberToken| |Generate|TOK:ZNR|Hydra|||GrakmawSkyclaveRavagerHydraToken| |Generate|TOK:ZNR|Illusion|||CustomIllusionToken| |Generate|TOK:ZNR|Insect|||InsectToken| @@ -1064,19 +1219,16 @@ |Generate|TOK:ZNR|Plant|||PlantToken| # ZNC -|Generate|TOK:ZNC|Bird|||BirdToken| |Generate|TOK:ZNC|Beast|||BeastToken2| +|Generate|TOK:ZNC|Bird|||BirdToken| |Generate|TOK:ZNC|Elemental|1||OmnathElementalToken| |Generate|TOK:ZNC|Elemental|2||ZendikarsRoilElementalToken| |Generate|TOK:ZNC|Faerie Rogue|||FaerieRogueToken| -# # OonaQueenFaerieRogueToken is FaerieRogueToken with additional blue color, but ZNC contains only one token - so don't use normal token for it #|Generate|TOK:ZNC|Faerie Rogue|||OonaQueenFaerieRogueToken| -# Germ token uses in chest and antology, but scryfall put it here -#|Generate|TOK:ZNC|Phyrexian Germ|||PhyrexianGermToken| -# |Generate|TOK:ZNC|Goblin Rogue|||GoblinRogueToken| |Generate|TOK:ZNC|Kor Ally|||KorAllyToken| +|Generate|TOK:ZNC|Phyrexian Germ|||PhyrexianGermToken| |Generate|TOK:ZNC|Rat|||RatToken| |Generate|TOK:ZNC|Saproling|||SaprolingToken| |Generate|TOK:ZNC|Thopter|||ThopterColorlessToken| @@ -1090,8 +1242,8 @@ |Generate|TOK:CMR|Elephant|||ElephantToken| |Generate|TOK:CMR|Elf Warrior|||ElfWarriorToken| |Generate|TOK:CMR|Golem|||GolemToken| -|Generate|TOK:CMR|Phyrexian Horror|||PhyrexianRebirthHorrorToken| |Generate|TOK:CMR|Illusion|||MelokuTheCloudedMirrorToken| +|Generate|TOK:CMR|Phyrexian Horror|||PhyrexianRebirthHorrorToken| |Generate|TOK:CMR|Plant|||PlantToken| |Generate|TOK:CMR|Rock|||RockToken| |Generate|TOK:CMR|Salamander Warrior|||SalamanderWarriorToken| @@ -1151,7 +1303,7 @@ |Generate|TOK:TSR|Soldier|||SoldierToken| |Generate|TOK:TSR|Spider|||PenumbraSpiderToken| -// STX +# STX |Generate|TOK:STX|Avatar|||BloodAvatarToken| |Generate|TOK:STX|Elemental|||Elemental44Token| |Generate|TOK:STX|Fractal|||FractalToken| @@ -1164,8 +1316,6 @@ |Generate|TOK:C21|Beast|1||BeastToken| |Generate|TOK:C21|Beast|2||BeastToken2| |Generate|TOK:C21|Boar|||Boar2Token| -# no need tokens for Eternalize ability, but scryfall have it: https://scryfall.com/card/tc21/6/champion-of-wits -# no need tokens for Copy, but scryfall have it: https://scryfall.com/card/tc21/30/copy |Generate|TOK:C21|Construct|1||MetallurgicSummoningsConstructToken| |Generate|TOK:C21|Construct|2||KarnConstructToken| |Generate|TOK:C21|Demon|||DemonFlyingToken| @@ -1192,7 +1342,7 @@ |Generate|TOK:C21|Wurm|||WurmToken| |Generate|TOK:C21|Zombie|||ZombieToken| -// MH2 +# MH2 |Generate|TOK:MH2|Beast|||BeastToken2| |Generate|TOK:MH2|Bird|||BirdToken| |Generate|TOK:MH2|Clue|1||ClueArtifactToken| @@ -1208,8 +1358,6 @@ |Generate|TOK:MH2|Phyrexian Germ|||PhyrexianGermToken| |Generate|TOK:MH2|Squirrel|||SquirrelToken| |Generate|TOK:MH2|Thopter|||ThopterColorlessToken| -# no need tokens for Eternalize ability, but scryfall have it: https://scryfall.com/card/tmh2/4/timeless-dragon -# no need tokens for Eternalize ability, but scryfall have it: https://scryfall.com/card/tmh2/5/timeless-witness |Generate|TOK:MH2|Treasure|1||TreasureToken| |Generate|TOK:MH2|Treasure|2||TreasureToken| |Generate|TOK:MH2|Zombie|||ZombieToken| @@ -1235,7 +1383,6 @@ # AFC |Generate|TOK:AFC|Angel|||AngelToken| |Generate|TOK:AFC|Beast|||BeastToken| -# no need tokens for Eternalize ability, but scryfall have it: https://scryfall.com/card/tafc/4/champion-of-wits |Generate|TOK:AFC|Clue|||ClueArtifactToken| |Generate|TOK:AFC|Dragon|||DragonToken2| |Generate|TOK:AFC|Dragon Spirit|||VrondissRageOfAncientsToken| @@ -1308,7 +1455,7 @@ # UMA |Generate|TOK:UMA|Citizen|||CitizenToken| |Generate|TOK:UMA|Drake|||DrakeToken| -|Generate|TOK:UMA|Elemental|1||WalkerOfTheGroveToken| +|Generate|TOK:UMA|Elemental|1||Elemental44GreenToken| |Generate|TOK:UMA|Elemental|2||RedElementalToken| |Generate|TOK:UMA|Elemental|3||RedElementalToken| |Generate|TOK:UMA|Faerie Rogue|||FaerieRogueToken| @@ -1357,18 +1504,45 @@ |Generate|TOK:NEC|Thopter|||ThopterColorlessToken| # SLD +|Generate|TOK:SLD|Angel|||AngelToken| +|Generate|TOK:SLD|Cat|1||GreenCatToken| +|Generate|TOK:SLD|Cat|2||CatToken2| +|Generate|TOK:SLD|Cat|3||CatToken2| |Generate|TOK:SLD|Clue|||ClueArtifactToken| +|Generate|TOK:SLD|Dog|||WhiteDogToken| +|Generate|TOK:SLD|Egg|||AtlaPalaniToken| |Generate|TOK:SLD|Faerie Rogue|1||FaerieRogueToken| |Generate|TOK:SLD|Faerie Rogue|2||FaerieRogueToken| |Generate|TOK:SLD|Faerie Rogue|3||FaerieRogueToken| |Generate|TOK:SLD|Faerie Rogue|4||FaerieRogueToken| -|Generate|TOK:SLD|Treasure|||TreasureToken| +|Generate|TOK:SLD|Food|1||FoodToken| +|Generate|TOK:SLD|Food|2||FoodToken| +|Generate|TOK:SLD|Food|3||FoodToken| +|Generate|TOK:SLD|Food|4||FoodToken| +|Generate|TOK:SLD|Food|5||FoodToken| +|Generate|TOK:SLD|Goblin|||GoblinToken| +|Generate|TOK:SLD|Hydra|||ZaxaraTheExemplaryHydraToken| +|Generate|TOK:SLD|Icingdeath, Frost Tongue|||IcingdeathFrostTongueToken| +|Generate|TOK:SLD|Marit Lage|||MaritLageToken| +|Generate|TOK:SLD|Mechtitan|||MechtitanToken| +|Generate|TOK:SLD|Saproling|||SaprolingToken| +|Generate|TOK:SLD|Shrine|||ShrineToken| +|Generate|TOK:SLD|Spirit|1||SpiritWhiteToken| +|Generate|TOK:SLD|Spirit|2||SpiritToken| +|Generate|TOK:SLD|Squirrel|||SquirrelToken| +|Generate|TOK:SLD|Treasure|1||TreasureToken| +|Generate|TOK:SLD|Treasure|2||TreasureToken| +|Generate|TOK:SLD|Treasure|3||TreasureToken| +|Generate|TOK:SLD|Treasure|4||TreasureToken| |Generate|TOK:SLD|Walker|1||WalkerToken| |Generate|TOK:SLD|Walker|2||WalkerToken| |Generate|TOK:SLD|Walker|3||WalkerToken| |Generate|TOK:SLD|Walker|4||WalkerToken| |Generate|TOK:SLD|Walker|5||WalkerToken| -# TODO: Add new SLD token images +|Generate|TOK:SLD|Warrior|||WarriorToken| +|Generate|TOK:SLD|Wolf|||WolfToken| +|Generate|TOK:SLD|Wurm|||WurmWithTrampleToken| +|Generate|TOK:SLD|Zombie|||ZombieToken| # 2XM |Generate|TOK:2XM|Angel|||AngelToken| @@ -1381,13 +1555,15 @@ |Generate|TOK:2XM|Elemental|||VoiceOfResurgenceToken| |Generate|TOK:2XM|Elephant|||ElephantToken| |Generate|TOK:2XM|Elf Warrior|||GreenWhiteElfWarriorToken| -|Generate|TOK:2XM|Phyrexian Germ|||PhyrexianGermToken| |Generate|TOK:2XM|Golem|||GolemToken| |Generate|TOK:2XM|Human Soldier|||HumanSoldierToken| |Generate|TOK:2XM|Marit Lage|||MaritLageToken| |Generate|TOK:2XM|Myr|||MyrToken| -|Generate|TOK:2XM|Phyrexian Myr|||BrudicladTelchorMyrToken| |Generate|TOK:2XM|Ooze|||OozeToken| +|Generate|TOK:2XM|Phyrexian Germ|||PhyrexianGermToken| +|Generate|TOK:2XM|Phyrexian Myr|||BrudicladTelchorMyrToken| +|Generate|TOK:2XM|Phyrexian Wurm|1||WurmWithDeathtouchToken| +|Generate|TOK:2XM|Phyrexian Wurm|2||WurmWithLifelinkToken| |Generate|TOK:2XM|Plant|||PlantToken| |Generate|TOK:2XM|Saproling|||SaprolingToken| |Generate|TOK:2XM|Servo|||ServoToken| @@ -1399,8 +1575,6 @@ |Generate|TOK:2XM|Treasure|||TreasureToken| |Generate|TOK:2XM|Tuktuk the Returned|||TuktukTheReturnedToken| |Generate|TOK:2XM|Wolf|||WolfToken| -|Generate|TOK:2XM|Phyrexian Wurm|1||WurmWithDeathtouchToken| -|Generate|TOK:2XM|Phyrexian Wurm|2||WurmWithLifelinkToken| # SNC |Generate|TOK:SNC|Angel|||Angel33Token| @@ -1482,20 +1656,20 @@ # CM2 |Generate|TOK:CM2|Bird|||BirdToken| |Generate|TOK:CM2|Elemental Shaman|||ElementalShamanToken| -|Generate|TOK:CM2|Phyrexian Germ|||PhyrexianGermToken| |Generate|TOK:CM2|Goat|||GoatToken| |Generate|TOK:CM2|Goblin|||GoblinToken| |Generate|TOK:CM2|Knight|||HuntedDragonKnightToken| |Generate|TOK:CM2|Lightning Rager|||LightningRagerToken| |Generate|TOK:CM2|Myr|||MyrToken| |Generate|TOK:CM2|Pentavite|||PentaviteToken| +|Generate|TOK:CM2|Phyrexian Germ|||PhyrexianGermToken| +|Generate|TOK:CM2|Phyrexian Wurm|1||WurmWithDeathtouchToken| +|Generate|TOK:CM2|Phyrexian Wurm|2||WurmWithLifelinkToken| |Generate|TOK:CM2|Saproling|||SaprolingToken| |Generate|TOK:CM2|Shapeshifter|||CribSwapShapeshifterWhiteToken| |Generate|TOK:CM2|Spirit|||SpiritWhiteToken| |Generate|TOK:CM2|Triskelavite|||TriskelaviteToken| |Generate|TOK:CM2|Tuktuk the Returned|||TuktukTheReturnedToken| -|Generate|TOK:CM2|Phyrexian Wurm|1||WurmWithDeathtouchToken| -|Generate|TOK:CM2|Phyrexian Wurm|2||WurmWithLifelinkToken| |Generate|TOK:CM2|Zombie|||ZombieToken| # PCA @@ -1507,13 +1681,13 @@ |Generate|TOK:PCA|Eldrazi Spawn|1||EldraziSpawnToken| |Generate|TOK:PCA|Eldrazi Spawn|2||EldraziSpawnToken| |Generate|TOK:PCA|Eldrazi Spawn|3||EldraziSpawnToken| -|Generate|TOK:PCA|Phyrexian Germ|||PhyrexianGermToken| |Generate|TOK:PCA|Goat|||GoatToken| |Generate|TOK:PCA|Goblin|||GoblinToken| |Generate|TOK:PCA|Hellion|||HellionToken| |Generate|TOK:PCA|Insect|||InsectToken| |Generate|TOK:PCA|Ooze|1||OozeToken| |Generate|TOK:PCA|Ooze|2||MitoticSlimeOozeToken| +|Generate|TOK:PCA|Phyrexian Germ|||PhyrexianGermToken| |Generate|TOK:PCA|Plant|||PlantToken| |Generate|TOK:PCA|Saproling|||SaprolingToken| |Generate|TOK:PCA|Spider|||PenumbraSpiderToken| @@ -1533,11 +1707,11 @@ |Generate|TOK:V16|Marit Lage|||MaritLageToken| # DDR -|Generate|TOK:DDR|Eldrazi Scion|||EldraziScionToken| |Generate|TOK:DDR|Demon|||DemonToken| -|Generate|TOK:DDR|Zombie Giant|||QuestForTheGravelordZombieToken| -|Generate|TOK:DDR|Elemental|||WalkerOfTheGroveToken| +|Generate|TOK:DDR|Eldrazi Scion|||EldraziScionToken| +|Generate|TOK:DDR|Elemental|||Elemental44GreenToken| |Generate|TOK:DDR|Plant|||PlantToken| +|Generate|TOK:DDR|Zombie Giant|||QuestForTheGravelordZombieToken| # DDS |Generate|TOK:DDS|Beast|||BeastToken2| @@ -2059,10 +2233,51 @@ |Generate|TOK:WOC|Virtuous|||VirtuousRoleToken| # WHO +|Generate|TOK:WHO|Alien|||AlienToken| |Generate|TOK:WHO|Alien Insect|||AlienInsectToken| +|Generate|TOK:WHO|Alien Salamander|||AlienSalamanderToken| +|Generate|TOK:WHO|Alien Warrior|||AlienWarriorToken| +|Generate|TOK:WHO|Beast|||BeastToken| +|Generate|TOK:WHO|Clue|1||ClueToken| +|Generate|TOK:WHO|Clue|2||ClueToken| +|Generate|TOK:WHO|Clue|3||ClueToken| +|Generate|TOK:WHO|Dalek|||DalekToken| +|Generate|TOK:WHO|Dinosaur|||DinosaurFlyingHasteToken| +|Generate|TOK:WHO|Fish|||FishNoAbilityToken| +|Generate|TOK:WHO|Food|1||FoodToken| +|Generate|TOK:WHO|Food|2||FoodToken| +|Generate|TOK:WHO|Food|3||FoodToken| +|Generate|TOK:WHO|Horse|||TheGirlInTheFireplaceHorseToken| +|Generate|TOK:WHO|Human|||TheEleventhHourToken| +|Generate|TOK:WHO|Human Noble|||TheGirlInTheFireplaceHumanNobleToken| +|Generate|TOK:WHO|Mark of the Rani|||MarkOfTheRaniToken| +|Generate|TOK:WHO|Soldier|||SoldierToken| +|Generate|TOK:WHO|Treasure|1||TreasureToken| +|Generate|TOK:WHO|Treasure|2||TreasureToken| +|Generate|TOK:WHO|Treasure|3||TreasureToken| +|Generate|TOK:WHO|Treasure|4||TreasureToken| +|Generate|TOK:WHO|Warrior|||WarriorToken| # PIP +|Generate|TOK:PIP|Alien|||Alien00Token| +|Generate|TOK:PIP|Clue|||ClueToken| +|Generate|TOK:PIP|Food|1||FoodToken| +|Generate|TOK:PIP|Food|2||FoodToken| +|Generate|TOK:PIP|Food|3||FoodToken| +|Generate|TOK:PIP|Human Knight|||ThePrydwenSteelFlagshipHumanKnightToken| +|Generate|TOK:PIP|Human Soldier|||HumanSoldierToken| +|Generate|TOK:PIP|Junk|||JunkToken| |Generate|TOK:PIP|Robot|||RobotToken| +|Generate|TOK:PIP|Settlement|||SettlementToken| +|Generate|TOK:PIP|Soldier|1||SoldierTokenWithHaste| +|Generate|TOK:PIP|Soldier|2||SoldierToken| +|Generate|TOK:PIP|Squirrel|||SquirrelToken| +|Generate|TOK:PIP|Thopter|||ThopterToken| +|Generate|TOK:PIP|Treasure|1||TreasureToken| +|Generate|TOK:PIP|Treasure|2||TreasureToken| +|Generate|TOK:PIP|Warrior|||WarriorToken| +|Generate|TOK:PIP|Wasteland Survival Guide|||WastelandSurvivalGuideToken| +|Generate|TOK:PIP|Zombie Mutant|||ZombieMutantToken| # LCI |Generate|TOK:LCI|Angel|||AngelVigilanceToken| @@ -2176,7 +2391,7 @@ |Generate|TOK:OTJ|Bird|||BlueBirdToken| |Generate|TOK:OTJ|Clue|||ClueArtifactToken| |Generate|TOK:OTJ|Dinosaur|||Dinosaur31Token| -|Generate|TOK:OTJ|Elemental|||SeedGuardianToken| +|Generate|TOK:OTJ|Elemental|||ElementalXXGreenToken| |Generate|TOK:OTJ|Elk|||ElkToken| |Generate|TOK:OTJ|Mercenary|||MercenaryToken| |Generate|TOK:OTJ|Meteorite|||MeteoriteToken| @@ -2460,7 +2675,7 @@ |Generate|TOK:DFT|Elephant|||ElephantToken| |Generate|TOK:DFT|Goblin|||GoblinToken| |Generate|TOK:DFT|Insect|||InsectToken| -|Generate|TOK:DFT|Pilot|||PilotCrewToken| +|Generate|TOK:DFT|Pilot|||PilotSaddleCrewToken| |Generate|TOK:DFT|Servo|||ServoToken| |Generate|TOK:DFT|Thopter|1||ThopterColorlessToken| |Generate|TOK:DFT|Thopter|2||ThopterColorlessToken| @@ -2482,20 +2697,44 @@ |Generate|TOK:DRC|Zombie Army|||ZombieArmyToken| |Generate|TOK:DRC|Zombie Warrior|||GodEternalOketraToken| +# TDM +|Generate|TOK:TDM|Bird|||BirdToken| +|Generate|TOK:TDM|Dragon|||DragonToken| +|Generate|TOK:TDM|Elephant|||Elephant55Token| +|Generate|TOK:TDM|Goblin|||GoblinToken| +|Generate|TOK:TDM|Monk|||MonasteryMentorToken| +|Generate|TOK:TDM|Reliquary Dragon|||ReliquaryDragonToken| +|Generate|TOK:TDM|Soldier|1||SoldierToken| +|Generate|TOK:TDM|Soldier|2||Soldier22Token| +|Generate|TOK:TDM|Spirit|1||SpiritXXToken| +|Generate|TOK:TDM|Spirit|2||NoFlyingSpiritWhiteToken| +# TODO: 2/2 Spirit (no relevant cards revealed, token not implemented) +# TODO: 3/3 Spirit (no relevant cards revealed, token not implemented) +|Generate|TOK:TDM|Treasure|||TreasureToken| +|Generate|TOK:TDM|Warrior|||RedWarriorToken| +|Generate|TOK:TDM|Zombie Druid|||ZombieDruidToken| + # TDC |Generate|TOK:TDC|Angel|||AngelVigilanceToken| +|Generate|TOK:TDC|Beast|||BeastToken| |Generate|TOK:TDC|Citizen|||CitizenGreenWhiteToken| |Generate|TOK:TDC|Dog|||WhiteDogToken| +|Generate|TOK:TDC|Dragon|1||DragonEggDragonToken| +|Generate|TOK:TDC|Dragon|2||DragonToken2| +|Generate|TOK:TDC|Dragon Egg|||NestingDragonToken| |Generate|TOK:TDC|Dragon Illusion|||DragonIllusionToken| |Generate|TOK:TDC|Eldrazi|||EldraziToken| |Generate|TOK:TDC|Elemental|1||RedElementalToken| |Generate|TOK:TDC|Elemental|2||Elemental11HasteToken| |Generate|TOK:TDC|Elemental|3||Elemental44Token| |Generate|TOK:TDC|First Mate Ragavan|||FirstMateRagavanToken| +|Generate|TOK:TDC|Frog Lizard|||FrogLizardToken| |Generate|TOK:TDC|Goat|||GoatToken| |Generate|TOK:TDC|Gold|||GoldToken| |Generate|TOK:TDC|Human|||HumanToken| +|Generate|TOK:TDC|Inkling|||InklingToken| |Generate|TOK:TDC|Insect|||InsectToken| +|Generate|TOK:TDC|Karox Bladewing|||KaroxBladewingToken| |Generate|TOK:TDC|Myr|||MyrToken| |Generate|TOK:TDC|Plant|||PlantToken| |Generate|TOK:TDC|Rat|||RatToken| @@ -2503,5 +2742,104 @@ |Generate|TOK:TDC|Servo|||ServoToken| |Generate|TOK:TDC|Snake|||OphiomancerSnakeToken| |Generate|TOK:TDC|Soldier|||SoldierArtifactToken| +|Generate|TOK:TDC|Spider|||SpiderToken| |Generate|TOK:TDC|Spirit|||SpiritWhiteToken| |Generate|TOK:TDC|Thopter|||ThopterColorlessToken| + +# ACR +|Generate|TOK:ACR|Assassin|||AssassinMenaceToken| +|Generate|TOK:ACR|Human Rogue|||HumanRogueToken| +|Generate|TOK:ACR|Phobos|||PhobosToken| +|Generate|TOK:ACR|Shapeshifter|||Shapeshifter32Token| +|Generate|TOK:ACR|Treasure|||TreasureToken| + +# DD2 +|Generate|TOK:DD2|Elemental Shaman|||ElementalShamanToken| + +# DSK +|Generate|TOK:DSK|Beast|||BeastieToken| +|Generate|TOK:DSK|Everywhere|||EverywhereToken| +|Generate|TOK:DSK|Glimmer|||GlimmerToken| +|Generate|TOK:DSK|Gremlin|||Gremlin11Token| +|Generate|TOK:DSK|Insect|1||InsectBlackGreenFlyingToken| +|Generate|TOK:DSK|Insect|2||InsectWhiteToken| +|Generate|TOK:DSK|Primo, the Indivisible|||PrimoTheIndivisibleToken| +|Generate|TOK:DSK|Shard|||ShardToken| +|Generate|TOK:DSK|Spider|||Spider22Token| +|Generate|TOK:DSK|Spirit|||SpiritBlueToken| +|Generate|TOK:DSK|Treasure|||TreasureToken| + +# FIN +|Generate|TOK:FIN|Food|||FoodToken| + +# JVC +|Generate|TOK:JVC|Elemental Shaman|||ElementalShamanToken| + +# REX +|Generate|TOK:REX|Dinosaur|||DinosaurToken| +|Generate|TOK:REX|Treasure|||TreasureToken| + +# UGL +|Generate|TOK:UGL|Goblin|||GoblinToken| +|Generate|TOK:UGL|Pegasus|||PegasusToken| +|Generate|TOK:UGL|Soldier|||SoldierToken| +|Generate|TOK:UGL|Squirrel|||SquirrelToken| +|Generate|TOK:UGL|Zombie|||ZombieToken| + +# F12 +|Generate|TOK:F12|Human|||HumanToken| +|Generate|TOK:F12|Wolf|||WolfToken| + +# F17 +|Generate|TOK:F17|Dinosaur|||DinosaurToken| +|Generate|TOK:F17|Pirate|||PirateToken| +|Generate|TOK:F17|Treasure|1||TreasureToken| +|Generate|TOK:F17|Treasure|2||TreasureToken| +|Generate|TOK:F17|Treasure|3||TreasureToken| +|Generate|TOK:F17|Vampire|||IxalanVampireToken| + +# HHO +|Generate|TOK:HHO|Treasure|||TreasureToken| + +# J12 +|Generate|TOK:J12|Centaur|||CentaurToken| + +# J13 +|Generate|TOK:J13|Golem|||HammerOfPurphorosGolemToken| + +# MPR +|Generate|TOK:MPR|Bear|||BearToken| +|Generate|TOK:MPR|Beast|||BeastToken2| +|Generate|TOK:MPR|Bird|||BlueBirdToken| +|Generate|TOK:MPR|Elephant|||ElephantToken| +|Generate|TOK:MPR|Goblin Soldier|||GoblinSoldierToken| +|Generate|TOK:MPR|Saproling|||SaprolingToken| +|Generate|TOK:MPR|Spirit|||SpiritWhiteToken| + +# P03 +|Generate|TOK:P03|Bear|||BearToken| +|Generate|TOK:P03|Bird|||RukhEggBirdToken| +|Generate|TOK:P03|Demon|||DemonFlyingToken| +|Generate|TOK:P03|Goblin|||GoblinToken| +|Generate|TOK:P03|Insect|||InsectToken| +|Generate|TOK:P03|Sliver|||SliverToken| + +# P04 +|Generate|TOK:P04|Angel|||AngelToken| +|Generate|TOK:P04|Beast|||BeastToken| +|Generate|TOK:P04|Myr|||MyrToken| +|Generate|TOK:P04|Pentavite|||PentaviteToken| +|Generate|TOK:P04|Spirit|||SpiritToken| + +# PEMN +|Generate|TOK:PEMN|Zombie|1||ZombieToken| +|Generate|TOK:PEMN|Zombie|2||ZombieToken| + +# PHEL +|Generate|TOK:PHEL|Angel|||AngelToken| + +# PL21 +|Generate|TOK:PL21|Minotaur|||MinotaurToken| + +# PL23 +|Generate|TOK:PL23|Food|||FoodToken| diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 92dc2faa708..473865c8d09 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -57200,6 +57200,7 @@ Cloud, Planet's Champion|Final Fantasy|552|M|{3}{R}{W}|Legendary Creature - Huma Sephiroth, Planet's Heir|Final Fantasy|553|M|{4}{U}{B}|Legendary Creature - Human Avatar Soldier|4|4|Vigilance$When Sephiroth enters, creatures your opponents control get -2/-2 until end of turn.$Whenever a creature an opponent controls dies, put a +1/+1 counter on Sephiroth.| Ugin, Eye of the Storms|Tarkir: Dragonstorm|1|M|{7}|Legendary Planeswalker - Ugin|7|When you cast this spell, exile up to one target permanent that's one or more colors.$Whenever you cast a colorless spell, exile up to one target permanent that's one or more colors.$+2: You gain 3 life and draw a card.$0: Add {C}{C}{C}.$-11: Search your library for any number of colorless nonland cards, exile them, then shuffle. Until end of turn, you may cast those cards without paying their mana costs.| Anafenza, Unyielding Lineage|Tarkir: Dragonstorm|2|R|{2}{W}|Legendary Creature - Spirit Soldier|2|2|Flash$First strike$Whenever another nontoken creature you control dies, Anafenza endures 2.| +Arashin Sunshield|Tarkir: Dragonstorm|3|C|{3}{W}|Creature - Human Warrior|3|4|When this creature enters, exile up to two target cards from a single graveyard.${W}, {T}: Tap target creature.| Bearer of Glory|Tarkir: Dragonstorm|4|C|{1}{W}|Creature - Human Soldier|2|1|During your turn, this creature has first strike.${4}{W}: Creatures you control get +1/+1 until end of turn.| Clarion Conqueror|Tarkir: Dragonstorm|5|R|{2}{W}|Creature - Dragon|3|3|Flying$Activated abilities of artifacts, creatures, and planeswalkers can't be activated.| Coordinated Maneuver|Tarkir: Dragonstorm|6|C|{1}{W}|Instant|||Choose one --$* Coordinated Maneuver deals damage equal to the number of creatures you control to target creature or planeswalker.$* Destroy target enchantment.| @@ -57209,10 +57210,12 @@ Dragonback Lancer|Tarkir: Dragonstorm|9|C|{3}{W}|Creature - Human Soldier|3|3|Fl Duty Beyond Death|Tarkir: Dragonstorm|10|U|{1}{W}|Instant|||As an additional cost to cast this spell, sacrifice a creature.$Creatures you control gain indestructible until end of turn. Put a +1/+1 counter on each creature you control.| Elspeth, Storm Slayer|Tarkir: Dragonstorm|11|M|{3}{W}{W}|Legendary Planeswalker - Elspeth|5|If one or more tokens would be created under your control, twice that many of those tokens are created instead.$+1: Create a 1/1 white Soldier creature token.$0: Put a +1/+1 counter on each creature you control. Those creatures gain flying until your next turn.$-3: Destroy target creature an opponent controls with mana value 3 or greater.| Fortress Kin-Guard|Tarkir: Dragonstorm|12|C|{1}{W}|Creature - Dog Soldier|1|2|When this creature enters, it endures 1.| +Furious Forebear|Tarkir: Dragonstorm|13|U|{1}{W}|Creature - Spirit Warrior|3|1|Whenever a creature you control dies while this card is in your graveyard, you may pay {1}{W}. If you do, return this card from your graveyard to your hand.| Lightfoot Technique|Tarkir: Dragonstorm|14|C|{1}{W}|Instant|||Put a +1/+1 counter on target creature. It gains flying and indestructible until end of turn.| Loxodon Battle Priest|Tarkir: Dragonstorm|15|U|{4}{W}|Creature - Elephant Cleric|3|5|At the beginning of combat on your turn, put a +1/+1 counter on another target creature you control.| Mardu Devotee|Tarkir: Dragonstorm|16|C|{W}|Creature - Human Scout|1|2|When this creature enters, scry 2.${1}: Add {R}, {W}, or {B}. Activate only once each turn.| Osseous Exhale|Tarkir: Dragonstorm|17|C|{1}{W}|Instant|||As an additional cost to cast this spell, you may behold a Dragon.$Osseous Exhale deals 5 damage to target attacking or blocking creature. If a Dragon was beheld, you gain 2 life.| +Poised Practitioner|Tarkir: Dragonstorm|18|C|{2}{W}|Creature - Human Monk|2|3|Flurry -- Whenever you cast your second spell each turn, put a +1/+1 counter on this creature. Scry 1.| Rally the Monastery|Tarkir: Dragonstorm|19|U|{3}{W}|Instant|||This spell costs {2} less to cast if you've cast another spell this turn.$Choose one --$* Create two 1/1 white Monk creature tokens with prowess.$* Up to two target creatures you control each get +2/+2 until end of turn.$* Destroy target creature with power 4 or greater.| Rebellious Strike|Tarkir: Dragonstorm|20|C|{1}{W}|Instant|||Target creature gets +3/+0 until end of turn.$Draw a card.| Riling Dawnbreaker|Tarkir: Dragonstorm|21|C|{4}{W}|Creature - Dragon|3|4|Flying, vigilance$At the beginning of combat on your turn, another target creature you control gets +1/+0 until end of turn.| @@ -57222,6 +57225,7 @@ Salt Road Packbeast|Tarkir: Dragonstorm|23|C|{5}{W}|Creature - Beast|4|3|This sp Smile at Death|Tarkir: Dragonstorm|24|M|{3}{W}{W}|Enchantment|||At the beginning of your upkeep, return up to two target creature cards with power 2 or less from your graveyard to the battlefield. Put a +1/+1 counter on each of those creatures.| Starry-Eyed Skyrider|Tarkir: Dragonstorm|25|U|{2}{W}|Creature - Human Scout|1|3|Flying$Whenever this creature attacks, another target creature you control gains flying until end of turn.$Attacking tokens you control have flying.| Static Snare|Tarkir: Dragonstorm|26|U|{4}{W}|Enchantment|||Flash$This spell costs {1} less to cast for each attacking creature.$When this enchantment enters, exile target artifact or creature an opponent controls until this enchantment leaves the battlefield.| +Stormbeacon Blade|Tarkir: Dragonstorm|27|U|{1}{W}|Artifact - Equipment|||Equipped creature gets +3/+0.$Whenever equipped creature attacks, draw a card if you control three or more attacking creatures.$Equip {2}| Stormplain Detainment|Tarkir: Dragonstorm|28|C|{2}{W}|Enchantment|||When this enchantment enters, exile target nonland permanent an opponent controls until this enchantment leaves the battlefield.| Sunpearl Kirin|Tarkir: Dragonstorm|29|U|{1}{W}|Creature - Kirin|2|1|Flash$Flying$When this creature enters, return up to one other target nonland permanent you control to its owner's hand. If it was a token, draw a card.| Teeming Dragonstorm|Tarkir: Dragonstorm|30|U|{3}{W}|Enchantment|||When this enchantment enters, create two 2/2 white Soldier creature tokens.$When a Dragon you control enters, return this enchantment to its owner's hand.| @@ -57233,21 +57237,26 @@ Aegis Sculptor|Tarkir: Dragonstorm|35|U|{3}{U}|Creature - Bird Wizard|2|3|Flying Agent of Kotis|Tarkir: Dragonstorm|36|C|{1}{U}|Creature - Human Rogue|2|1|Renew -- {3}{U}, Exile this card from your graveyard: Put two +1/+1 counters on target creature. Activate only as a sorcery.| Ambling Stormshell|Tarkir: Dragonstorm|37|R|{3}{U}{U}|Creature - Turtle|5|9|Ward {2}$Whenever this creature attacks, put three stun counters on it and draw three cards.$Whenever you cast a Turtle spell, untap this creature.| Bewildering Blizzard|Tarkir: Dragonstorm|38|U|{4}{U}{U}|Instant|||Draw three cards. Creatures your opponents control get -3/-0 until end of turn.| +Constrictor Sage|Tarkir: Dragonstorm|39|U|{4}{U}|Creature - Snake Wizard|4|4|When this creature enters, tap target creature an opponent controls and put a stun counter on it.$Renew -- {2}{U}, Exile this card from your graveyard: Tap target creature an opponent controls and put a stun counter on it. Activate only as a sorcery.| Dirgur Island Dragon|Tarkir: Dragonstorm|40|C|{5}{U}|Creature - Dragon|4|4|Flying$Ward {2}| Skimming Strike|Tarkir: Dragonstorm|40|C|{1}{U}|Instant - Omen|4|4|Tap up to one target creature. Draw a card.| Dispelling Exhale|Tarkir: Dragonstorm|41|C|{1}{U}|Instant|||As an additional cost to cast this spell, you may behold a Dragon.$Counter target spell unless its controller pays {2}. If a Dragon was beheld, counter that spell unless its controller pays {4} instead.| Dragonologist|Tarkir: Dragonstorm|42|R|{2}{U}|Creature - Human Wizard|1|3|When this creature enters, look at the top six cards of your library. You may reveal an instant, sorcery, or Dragon card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.$Untapped Dragons you control have hexproof.| Dragonstorm Forecaster|Tarkir: Dragonstorm|43|U|{U}|Creature - Human Scout|0|3|{2}, {T}: Search your library for a card named Dragonstorm Globe or Boulderborn Dragon, reveal it, put it into your hand, then shuffle.| Essence Anchor|Tarkir: Dragonstorm|44|U|{2}{U}|Artifact|||At the beginning of your upkeep, surveil 1.${T}: Create a 2/2 black Zombie Druid creature token. Activate only during your turn and only if a card left your graveyard this turn.| +Focus the Mind|Tarkir: Dragonstorm|45|C|{4}{U}|Instant|||This spell costs {2} less to cast if you've cast another spell this turn.$Draw three cards, then discard a card.| Fresh Start|Tarkir: Dragonstorm|46|U|{1}{U}|Enchantment - Aura|||Flash$Enchant creature$Enchanted creature gets -5/-0 and loses all abilities.| Highspire Bell-Ringer|Tarkir: Dragonstorm|47|C|{2}{U}|Creature - Djinn Monk|1|4|Flying$The second spell you cast each turn costs {1} less to cast.| Humbling Elder|Tarkir: Dragonstorm|48|C|{U}|Creature - Human Monk|1|2|Flash$When this creature enters, target creature an opponent controls gets -2/-0 until end of turn.| +Iceridge Serpent|Tarkir: Dragonstorm|49|C|{4}{U}|Creature - Serpent|3|3|When this creature enters, return target creature an opponent controls to its owner's hand.| Kishla Trawlers|Tarkir: Dragonstorm|50|U|{2}{U}|Creature - Human Citizen|3|2|When this creature enters, you may exile a creature card from your graveyard. When you do, return target instant or sorcery card from your graveyard to your hand.| Marang River Regent|Tarkir: Dragonstorm|51|R|{4}{U}{U}|Creature - Dragon|6|7|Flying$When this creature enters, return up to two other target nonland permanents to their owners' hands.| Coil and Catch|Tarkir: Dragonstorm|51|R|{3}{U}|Instant - Omen|6|7|Draw three cards, then discard a card.| Naga Fleshcrafter|Tarkir: Dragonstorm|52|R|{3}{U}|Creature - Snake Shapeshifter|0|0|You may have this creature enter as a copy of any creature on the battlefield.$Renew -- {2}{U}, Exile this card from your graveyard: Put a +1/+1 counter on target nonlegendary creature you control. Each other creature you control becomes a copy of that creature until end of turn. Activate only as a sorcery.| Ringing Strike Mastery|Tarkir: Dragonstorm|53|C|{U}|Enchantment - Aura|||Enchant creature$When this Aura enters, tap enchanted creature.$Enchanted creature doesn't untap during its controller's untap step.$Enchanted creature has "{5}: Untap this creature."| +Riverwalk Technique|Tarkir: Dragonstorm|54|C|{3}{U}|Instant|||Choose one --$* The owner of target nonland permanent puts it on their choice of the top or bottom of their library.$* Counter target noncreature spell.| Roiling Dragonstorm|Tarkir: Dragonstorm|55|U|{1}{U}|Enchantment|||When this enchantment enters, draw two cards, then discard a card.$When a Dragon you control enters, return this enchantment to its owner's hand.| +Sibsig Appraiser|Tarkir: Dragonstorm|56|C|{2}{U}|Creature - Zombie Advisor|2|1|When this creature enters, look at the top two cards of your library. Put one of them into your hand and the other into your graveyard.| Snowmelt Stag|Tarkir: Dragonstorm|57|C|{3}{U}|Creature - Elemental Elk|2|5|Vigilance$During your turn, this creature has base power and toughness 5/2.${5}{U}{U}: This creature can't be blocked this turn.| Spectral Denial|Tarkir: Dragonstorm|58|U|{X}{U}|Instant|||This spell costs {1} less to cast for each creature you control with power 4 or greater.$Counter target spell unless its controller pays {X}.| Stillness in Motion|Tarkir: Dragonstorm|59|R|{1}{U}|Enchantment|||At the beginning of your upkeep, mill three cards. Then if you have no cards in your library, exile this enchantment and put five cards from your graveyard on top of your library in any order.| @@ -57255,9 +57264,14 @@ Taigam, Master Opportunist|Tarkir: Dragonstorm|60|M|{1}{U}|Legendary Creature - Temur Devotee|Tarkir: Dragonstorm|61|C|{1}{U}|Creature - Human Druid|3|3|Defender${1}: Add {G}, {U}, or {R}. Activate only once each turn.| Unending Whisper|Tarkir: Dragonstorm|62|C|{U}|Sorcery|||Draw a card.$Harmonize {5}{U}| Ureni's Rebuff|Tarkir: Dragonstorm|63|U|{1}{U}|Sorcery|||Return target creature to its owner's hand.$Harmonize {5}{U}| +Veteran Ice Climber|Tarkir: Dragonstorm|64|U|{1}{U}|Creature - Human Scout|1|3|Vigilance$This creature can't be blocked.$Whenever this creature attacks, up to one target player mills cards equal to this creature's power.| +Wingblade Disciple|Tarkir: Dragonstorm|65|U|{2}{U}|Creature - Human Monk|2|2|Flying$Flurry -- Whenever you cast your second spell each turn, create a 1/1 white Bird creature token with flying.| Wingspan Stride|Tarkir: Dragonstorm|66|C|{U}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +1/+1 and has flying.${2}{U}: Return this Aura to its owner's hand.| Winternight Stories|Tarkir: Dragonstorm|67|R|{2}{U}|Sorcery|||Draw three cards. Then discard two cards unless you discard a creature card.$Harmonize {4}{U}| Abzan Devotee|Tarkir: Dragonstorm|68|C|{1}{B}|Creature - Dog Cleric|2|1|{1}: Add {W}, {B}, or {G}. Activate only once each turn.${2}{B}: Return this card from your graveyard to your hand.| +Adorned Crocodile|Tarkir: Dragonstorm|69|C|{4}{B}|Creature - Crocodile|5|3|When this creature dies, create a 2/2 black Zombie Druid creature token. Renew -, Exile this card from your graveyard: Put a +1/+1 counter on target creature. Activate only as a sorcery.| +Aggressive Negotiations|Tarkir: Dragonstorm|70|C|{2}{B}|Sorcery|||Target opponent reveals their hand. You choose a nonland card from it and exile that card. Put a +1/+1 counter on up to one target creature you control.| +Alchemist's Assistant|Tarkir: Dragonstorm|71|U|{1}{B}|Creature - Monkey|2|1|Lifelink$Renew -- {1}{B}, Exile this card from your graveyard: Put a lifelink counter on target creature. Activate only as a sorcery.| Alesha's Legacy|Tarkir: Dragonstorm|72|C|{1}{B}|Instant|||Target creature you control gains deathtouch and indestructible until end of turn.| Avenger of the Fallen|Tarkir: Dragonstorm|73|R|{2}{B}|Creature - Human Warrior|2|4|Deathtouch$Mobilize X, where X is the number of creature cards in your graveyard.| Caustic Exhale|Tarkir: Dragonstorm|74|C|{B}|Instant|||As an additional cost to cast this spell, behold a Dragon or pay {1}.$Target creature gets -3/-3 until end of turn.| @@ -57268,14 +57282,22 @@ Desperate Measures|Tarkir: Dragonstorm|78|U|{B}|Instant|||Target creature gets + Dragon's Prey|Tarkir: Dragonstorm|79|C|{2}{B}|Instant|||This spell costs {2} more to cast if it targets a Dragon.$Destroy target creature.| Feral Deathgorger|Tarkir: Dragonstorm|80|C|{5}{B}|Creature - Dragon|3|5|Flying, deathtouch$When this creature enters, exile up to two target cards from a single graveyard.| Dusk Sight|Tarkir: Dragonstorm|80|C|{1}{B}|Sorcery - Omen|3|5|Put a +1/+1 counter on up to one target creature. Draw a card.| +Gurmag Rakshasa|Tarkir: Dragonstorm|81|U|{4}{B}{B}|Creature - Demon|5|5|Menace$When this creature enters, target creature an opponent controls gets -2/-2 until end of turn and target creature you control gets +2/+2 until end of turn.| +Hundred-Battle Veteran|Tarkir: Dragonstorm|82|U|{3}{B}|Creature - Zombie Warrior|4|2|As long as there are three or more different kinds of counters among creatures you control, this creature gets +2/+4.$You may cast this card from your graveyard. If you do, it enters with a finality counter on it.| +Kin-Tree Nurturer|Tarkir: Dragonstorm|83|C|{2}{B}|Creature - Human Druid|2|1|Lifelink$When this creature enters, it endures 1.| Krumar Initiate|Tarkir: Dragonstorm|84|U|{1}{B}|Creature - Human Cleric|2|2|{X}{B}, {T}, Pay X life: This creature endures X. Activate only as a sorcery.| +Nightblade Brigade|Tarkir: Dragonstorm|85|C|{2}{B}|Creature - Goblin Soldier|1|3|Deathtouch$Mobilize 1$When this creature enters, surveil 1.| Qarsi Revenant|Tarkir: Dragonstorm|86|R|{1}{B}{B}|Creature - Vampire|3|3|Flying, deathtouch, lifelink$Renew -- {2}{B}, Exile this card from your graveyard: Put a flying counter, a deathtouch counter, and a lifelink counter on target creature. Activate only as a sorcery.| Rot-Curse Rakshasa|Tarkir: Dragonstorm|87|M|{1}{B}|Creature - Demon|5|5|Trample$Decayed$Renew -- {X}{B}{B}, Exile this card from your graveyard: Put a decayed counter on each of X target creatures. Activate only as a sorcery.| +Salt Road Skirmish|Tarkir: Dragonstorm|88|U|{3}{B}|Sorcery|||Destroy target creature. Create two 1/1 red Warrior creature tokens. They gain haste until end of turn. Sacrifice them at the beginning of the next end step.| +Sandskitter Outrider|Tarkir: Dragonstorm|89|C|{3}{B}|Creature - Goblin Soldier|2|1|Menace$When this creature enters, it endures 2.| Scavenger Regent|Tarkir: Dragonstorm|90|R|{3}{B}|Creature - Dragon|4|4|Flying$Ward--Discard a card.| Exude Toxin|Tarkir: Dragonstorm|90|R|{X}{B}{B}|Sorcery - Omen|4|4|Each non-Dragon creature gets -X/-X until end of turn.| The Sibsig Ceremony|Tarkir: Dragonstorm|91|R|{B}{B}{B}|Legendary Enchantment|||Creature spells you cast cost {2} less to cast.$Whenever a creature you control enters, if you cast it, destroy that creature, then create a 2/2 black Zombie Druid creature token.| Sidisi, Regent of the Mire|Tarkir: Dragonstorm|92|R|{1}{B}|Legendary Creature - Zombie Snake Warlock|1|3|{T}, Sacrifice a creature you control with mana value X other than Sidisi: Return target creature card with mana value X plus 1 from your graveyard to the battlefield. Activate only as a sorcery.| Sinkhole Surveyor|Tarkir: Dragonstorm|93|R|{1}{B}|Creature - Bird Scout|1|3|Flying$Whenever this creature attacks, you lose 1 life and this creature endures 1.| +Strategic Betrayal|Tarkir: Dragonstorm|94|U|{1}{B}|Sorcery|||Target opponent exiles a creature they control and their graveyard.| +Unburied Earthcarver|Tarkir: Dragonstorm|95|C|{1}{B}|Creature - Human Warrior|2|2|{2}, Sacrifice another creature: Put a +1/+1 counter on this creature.| Unrooted Ancestor|Tarkir: Dragonstorm|96|U|{2}{B}|Creature - Spirit Cleric|3|2|Flash${1}, Sacrifice another creature: This creature gains indestructible until end of turn. Tap it.| Venerated Stormsinger|Tarkir: Dragonstorm|97|U|{3}{B}|Creature - Orc Cleric|3|3|Mobilize 1$Whenever this creature or another creature you control dies, each opponent loses 1 life and you gain 1 life.| Wail of War|Tarkir: Dragonstorm|98|U|{2}{B}|Instant|||Choose one --$* Creatures target opponent controls get -1/-1 until end of turn.$* Return up to two target creature cards from your graveyard to your hand.| @@ -57288,41 +57310,57 @@ Devoted Duelist|Tarkir: Dragonstorm|104|C|{1}{R}|Creature - Goblin Monk|2|1|Hast Dracogenesis|Tarkir: Dragonstorm|105|M|{6}{R}{R}|Enchantment|||You may cast Dragon spells without paying their mana costs.| Equilibrium Adept|Tarkir: Dragonstorm|106|U|{3}{R}|Creature - Dog Monk|2|4|When this creature enters, exile the top card of your library. Until the end of your next turn, you may play that card.$Flurry -- Whenever you cast your second spell each turn, this creature gains double strike until end of turn.| Fire-Rim Form|Tarkir: Dragonstorm|107|C|{1}{R}|Enchantment - Aura|||Flash$Enchant creature$When this Aura enters, enchanted creature gains first strike until end of turn.$Enchanted creature gets +2/+0.| +Fleeting Effigy|Tarkir: Dragonstorm|108|U|{R}|Creature - Elemental|2|2|Haste$At the beginning of your end step, return this creature to its owner's hand.$2{R}: This creature gets +2/+0 until end of turn.| +Iridescent Tiger|Tarkir: Dragonstorm|109|U|{4}{R}|Creature - Cat|3|4|When this creature enters, if you cast it, add {W}{U}{B}{R}{G}.| Jeskai Devotee|Tarkir: Dragonstorm|110|C|{1}{R}|Creature - Orc Monk|2|2|Flurry -- Whenever you cast your second spell each turn, this creature gets +1/+1 until end of turn.${1}: Add {U}, {R}, or {W}. Activate only once each turn.| Magmatic Hellkite|Tarkir: Dragonstorm|111|R|{2}{R}{R}|Creature - Dragon|4|5|Flying$When this creature enters, destroy target nonbasic land an opponent controls. Its controller searches their library for a basic land card, puts it onto the battlefield tapped with a stun counter on it, then shuffles.| Meticulous Artisan|Tarkir: Dragonstorm|112|C|{3}{R}|Creature - Djinn Artificer|3|3|Prowess$When this creature enters, create a Treasure token.| Molten Exhale|Tarkir: Dragonstorm|113|C|{1}{R}|Sorcery|||You may cast this spell as though it had flash if you behold a Dragon as an additional cost to cast it.$Molten Exhale deals 4 damage to target creature or planeswalker.| Narset's Rebuke|Tarkir: Dragonstorm|114|C|{4}{R}|Instant|||Narset's Rebuke deals 5 damage to target creature. Add {U}{R}{W}. If that creature would die this turn, exile it instead.| +Overwhelming Surge|Tarkir: Dragonstorm|115|U|{2}{R}|Instant|||Choose one or both --$* Overwhelming Surge deals 3 damage to target creature.$* Destroy target noncreature artifact.| +Rescue Leopard|Tarkir: Dragonstorm|116|C|{2}{R}|Creature - Cat|4|2|Whenever this creature becomes tapped, you may discard a card. If you do, draw a card.| Reverberating Summons|Tarkir: Dragonstorm|117|U|{1}{R}|Enchantment|||At the beginning of each combat, if you've cast two or more spells this turn, this enchantment becomes a 3/3 Monk creature with haste in addition to its other types until end of turn.${1}{R}, Discard your hand, Sacrifice this enchantment: Draw two cards.| Sarkhan, Dragon Ascendant|Tarkir: Dragonstorm|118|R|{1}{R}|Legendary Creature - Human Druid|2|2|When Sarkhan enters, you may behold a Dragon. If you do, create a Treasure token.$Whenever a Dragon you control enters, put a +1/+1 counter on Sarkhan. Until end of turn, Sarkhan becomes a Dragon in addition to its other types and gains flying.| Seize Opportunity|Tarkir: Dragonstorm|119|C|{2}{R}|Instant|||Choose one --$* Exile the top two cards of your library. Until the end of your next turn, you may play those cards.$* Up to two target creatures each get +2/+1 until end of turn.| Shock Brigade|Tarkir: Dragonstorm|120|C|{1}{R}|Creature - Goblin Soldier|1|3|Menace$Mobilize 1| Shocking Sharpshooter|Tarkir: Dragonstorm|121|U|{1}{R}|Creature - Human Archer|1|3|Reach$Whenever another creature you control enters, this creature deals 1 damage to target opponent.| +Stadium Headliner|Tarkir: Dragonstorm|122|R|{R}|Creature - Goblin Warrior|1|1|Mobilize 1${1}{R}, Sacrifice this creature: It deals damage equal to the number of creatures you control to target creature.| Stormscale Scion|Tarkir: Dragonstorm|123|M|{4}{R}{R}|Creature - Dragon|4|4|Flying$Other Dragons you control get +1/+1.$Storm| Stormshriek Feral|Tarkir: Dragonstorm|124|C|{4}{R}|Creature - Dragon|3|3|Flying, haste${1}{R}: This creature gets +1/+0 until end of turn.| Flush Out|Tarkir: Dragonstorm|124|C|{1}{R}|Sorcery - Omen|3|3|Discard a card. If you do, draw two cards.| Summit Intimidator|Tarkir: Dragonstorm|125|C|{3}{R}|Creature - Yeti|4|3|Reach$When this creature enters, target creature can't block this turn.| Sunset Strikemaster|Tarkir: Dragonstorm|126|U|{1}{R}|Creature - Human Monk|3|1|{T}: Add {R}.${2}{R}, {T}, Sacrifice this creature: It deals 6 damage to target creature with flying.| Tersa Lightshatter|Tarkir: Dragonstorm|127|R|{2}{R}|Legendary Creature - Orc Wizard|3|3|Haste$When Tersa Lightshatter enters, discard up to two cards, then draw that many cards.$Whenever Tersa Lightshatter attacks, if there are seven or more cards in your graveyard, exile a card at random from your graveyard. You may play that card this turn.| +Twin Bolt|Tarkir: Dragonstorm|128|C|{1}{R}|Instant|||Twin Bolt deals 2 damage divided as you choose among one or two targets.| Underfoot Underdogs|Tarkir: Dragonstorm|129|C|{2}{R}|Creature - Goblin Warrior|1|2|When this creature enters, create a 1/1 red Goblin creature token.${1}, {T}: Target creature you control with power 2 or less can't be blocked this turn.| Unsparing Boltcaster|Tarkir: Dragonstorm|130|U|{2}{R}|Creature - Ogre Wizard|3|3|When this creature enters, it deals 5 damage to target creature an opponent controls that was dealt damage this turn.| War Effort|Tarkir: Dragonstorm|131|U|{3}{R}|Enchantment|||Creatures you control get +1/+0.$Whenever you attack, create a 1/1 red Warrior creature token that's tapped and attacking. Sacrifice it at the beginning of the next end step.| +Wild Ride|Tarkir: Dragonstorm|132|C|{R}|Sorcery|||Target creature gets +3/+0 and gains haste until end of turn.$Harmonize {4}{R}| Zurgo's Vanguard|Tarkir: Dragonstorm|133|U|{2}{R}|Creature - Dog Soldier|*|3|Mobilize 1$This creature's power is equal to the number of creatures you control.| +Ainok Wayfarer|Tarkir: Dragonstorm|134|C|{1}{G}|Creature - Dog Scout|1|1|When this creature enters, mill three cards. You may put a land card from among them into your hand. If you don't, put a +1/+1 counter on this creature.| Attuned Hunter|Tarkir: Dragonstorm|135|U|{2}{G}|Creature - Human Ranger|3|3|Trample$Whenever one or more cards leave your graveyard during your turn, put a +1/+1 counter on this creature.| Bloomvine Regent|Tarkir: Dragonstorm|136|R|{3}{G}{G}|Creature - Dragon|4|5|Flying$Whenever this creature or another Dragon you control enters, you gain 3 life.| Claim Territory|Tarkir: Dragonstorm|136|R|{2}{G}|Sorcery - Omen|4|5|Search your library for up to two basic Forest cards, reveal them, put one onto the battlefield tapped and the other into your hand, then shuffle.| +Champion of Dusan|Tarkir: Dragonstorm|137|C|{2}{G}|Creature - Human Warrior|4|2|Trample$Renew -- {1}{G}, Exile this card from your graveyard: Put a +1/+1 counter and a trample counter on target creature. Activate only as a sorcery.| Craterhoof Behemoth|Tarkir: Dragonstorm|138|M|{5}{G}{G}{G}|Creature - Beast|5|5|Haste$When this creature enters, creatures you control gain trample and get +X/+X until end of turn, where X is the number of creatures you control.| +Dragon Sniper|Tarkir: Dragonstorm|139|U|{G}|Creature - Human Archer|1|1|Vigilance, reach, deathtouch| Dragonbroods' Relic|Tarkir: Dragonstorm|140|U|{1}{G}|Artifact|||{T}, Tap an untapped creature you control: Add one mana of any color.${3}{W}{U}{B}{R}{G}, Sacrifice this artifact: Create a 4/4 Dragon creature token named Reliquary Dragon that's all colors. It has flying, lifelink, and "When this token enters, it deals 3 damage to any target." Activate only as a sorcery.| Dusyut Earthcarver|Tarkir: Dragonstorm|141|C|{5}{G}|Creature - Elephant Druid|4|4|Reach$When this creature enters, it endures 3.| Encroaching Dragonstorm|Tarkir: Dragonstorm|142|U|{3}{G}|Enchantment|||When this enchantment enters, search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle.$When a Dragon you control enters, return this enchantment to its owner's hand.| +Formation Breaker|Tarkir: Dragonstorm|143|U|{1}{G}|Creature - Beast|2|1|Creatures with power less than this creature's power can't block it.$As long as you control a creature with a counter on it, this creature gets +1/+2.| Herd Heirloom|Tarkir: Dragonstorm|144|R|{1}{G}|Artifact|||{T}: Add one mana of any color. Spend this mana only to cast a creature spell.${T}: Until end of turn, target creature you control with power 4 or greater gains trample and "Whenever this creature deals combat damage to a player, draw a card."| Heritage Reclamation|Tarkir: Dragonstorm|145|C|{1}{G}|Instant|||Choose one --$* Destroy target artifact.$* Destroy target enchantment.$* Exile up to one target card from a graveyard. Draw a card.| +Inspirited Vanguard|Tarkir: Dragonstorm|146|U|{4}{G}|Creature - Human Soldier|3|2|Whenever this creature enters or attacks, it endures 2.| +Knockout Maneuver|Tarkir: Dragonstorm|147|U|{2}{G}|Sorcery|||Put a +1/+1 counter on target creature you control, then it deals damage equal to its power to target creature an opponent controls.| Krotiq Nestguard|Tarkir: Dragonstorm|148|C|{2}{G}|Creature - Insect|4|4|Defender${2}{G}: This creature can attack this turn as though it didn't have defender.| Lasyd Prowler|Tarkir: Dragonstorm|149|R|{2}{G}{G}|Creature - Snake Ranger|5|5|When this creature enters, you may mill cards equal to the number of lands you control.$Renew -- {1}{G}, Exile this card from your graveyard: Put X +1/+1 counters on target creature, where X is the number of land cards in your graveyard. Activate only as a sorcery.| Nature's Rhythm|Tarkir: Dragonstorm|150|R|{X}{G}{G}|Sorcery|||Search your library for a creature card with mana value X or less, put it onto the battlefield, then shuffle.$Harmonize {X}{G}{G}{G}{G}| Piercing Exhale|Tarkir: Dragonstorm|151|C|{1}{G}|Instant|||As an additional cost to cast this spell, you may behold a Dragon.$Target creature you control deals damage equal to its power to target creature or planeswalker. If a Dragon was beheld, surveil 2.| +Rainveil Rejuvenator|Tarkir: Dragonstorm|152|U|{3}{G}|Creature - Elephant Druid|2|4|When this creature enters, you may mill three cards.${T}: Add an amount of {G} equal to this creature's power.| Rite of Renewal|Tarkir: Dragonstorm|153|U|{3}{G}|Sorcery|||Return up to two target permanent cards from your graveyard to your hand. Target player shuffles up to four target cards from their graveyard into their library. Exile Rite of Renewal.| Roamer's Routine|Tarkir: Dragonstorm|154|C|{2}{G}|Sorcery|||Search your library for a basic land card, put it onto the battlefield tapped, then shuffle.$Harmonize {4}{G}| +Sage of the Fang|Tarkir: Dragonstorm|155|U|{2}{G}|Creature - Human Druid|2|2|When this creature enters, put a +1/+1 counter on target creature.$Renew -- {3}{G}, Exile this card from your graveyard: Put a +1/+1 counter on target creature, then double the number of +1/+1 counters on that creature.| +Sagu Pummeler|Tarkir: Dragonstorm|156|C|{3}{G}|Creature - Beast|4|4|Reach$Renew -- {4}{G}, Exile this card from your graveyard: Put two +1/+1 counters and a reach counter on target creature. Activate only as a sorcery.| Sagu Wildling|Tarkir: Dragonstorm|157|C|{4}{G}|Creature - Dragon|3|3|Flying$When this creature enters, you gain 3 life.| Roost Seek|Tarkir: Dragonstorm|157|C|{G}|Sorcery - Omen|3|3|Search your library for a basic land card, reveal it, put it into your hand, then shuffle.| Sarkhan's Resolve|Tarkir: Dragonstorm|158|C|{1}{G}|Instant|||Choose one --$* Target creature gets +3/+3 until end of turn.$* Destroy target creature with flying.| @@ -57330,11 +57368,12 @@ Snakeskin Veil|Tarkir: Dragonstorm|159|C|{G}|Instant|||Put a +1/+1 counter on ta Sultai Devotee|Tarkir: Dragonstorm|160|C|{1}{G}|Creature - Zombie Snake Druid|2|1|Deathtouch${1}: Add {B}, {G}, or {U}. Activate only once each turn.| Surrak, Elusive Hunter|Tarkir: Dragonstorm|161|R|{2}{G}|Legendary Creature - Human Warrior|4|3|This spell can't be countered.$Trample$Whenever a creature you control or a creature spell you control becomes the target of a spell or ability an opponent controls, draw a card.| Synchronized Charge|Tarkir: Dragonstorm|162|U|{1}{G}|Sorcery|||Distribute two +1/+1 counters among one or two target creatures you control. Creatures you control with counters on them gain vigilance and trample until end of turn.$Harmonize {4}{G}| +Trade Route Envoy|Tarkir: Dragonstorm|163|C|{3}{G}|Creature - Dog Soldier|4|3|When this creature enters, draw a card if you control a creature with a counter on it. If you don't draw a card this way, put a +1/+1 counter on this creature.| Traveling Botanist|Tarkir: Dragonstorm|164|U|{1}{G}|Creature - Dog Scout|2|3|Whenever this creature becomes tapped, look at the top card of your library. If it's a land card, you may reveal it and put it into your hand. If you don't put the card into your hand, you may put it into your graveyard.| Undergrowth Leopard|Tarkir: Dragonstorm|165|C|{1}{G}|Creature - Cat|2|2|Vigilance${1}, Sacrifice this creature: Destroy target artifact or enchantment.| Warden of the Grove|Tarkir: Dragonstorm|166|R|{2}{G}|Creature - Hydra|2|2|At the beginning of your end step, put a +1/+1 counter on this creature.$Whenever another nontoken creature you control enters, it endures X, where X is the number of counters on this creature.| All-Out Assault|Tarkir: Dragonstorm|167|M|{2}{R}{W}{B}|Enchantment|||Creatures you control get +1/+1 and have deathtouch.$When this enchantment enters, if it's your main phase, there is an additional combat phase after this phase followed by an additional main phase. When you next attack this turn, untap each creature you control.| -Armament Dragon|Tarkir: Dragonstorm|168|U|{3}{W}{B}{G}|Creature -- Dragon|3|4|Flying$When this creature enters, distribute three +1/+1 counters among one, two, or three target creatures you control.| +Armament Dragon|Tarkir: Dragonstorm|168|U|{3}{W}{B}{G}|Creature - Dragon|3|4|Flying$When this creature enters, distribute three +1/+1 counters among one, two, or three target creatures you control.| Auroral Procession|Tarkir: Dragonstorm|169|U|{G}{U}|Instant|||Return target card from your graveyard to your hand.| Awaken the Honored Dead|Tarkir: Dragonstorm|170|R|{B}{G}{U}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I -- Destroy target nonland permanent.$II -- Mill three cards.$III -- You may discard a card. When you do, return target creature or land card from your graveyard to your hand.| Barrensteppe Siege|Tarkir: Dragonstorm|171|R|{2}{W}{B}|Enchantment|||As this enchantment enters, choose Abzan or Mardu.$* Abzan -- At the beginning of your end step, put a +1/+1 counter on each creature you control.$* Mardu -- At the beginning of your end step, if a creature died under your control this turn, each opponent sacrifices a creature of their choice.| @@ -57347,6 +57386,7 @@ Defibrillating Current|Tarkir: Dragonstorm|177|U|{2/R}{2/W}{2/B}|Sorcery|||Defib Disruptive Stormbrood|Tarkir: Dragonstorm|178|U|{4}{G}|Creature - Dragon|3|3|Flying$When this creature enters, destroy up to one target artifact or enchantment.| Petty Revenge|Tarkir: Dragonstorm|178|U|{1}{B}|Sorcery - Omen|3|3|Destroy target creature with power 3 or less.| Dragonback Assault|Tarkir: Dragonstorm|179|M|{3}{G}{U}{R}|Enchantment|||When this enchantment enters, it deals 3 damage to each creature and each planeswalker.$Landfall -- Whenever a land you control enters, create a 4/4 red Dragon creature token with flying.| +Dragonclaw Strike|Tarkir: Dragonstorm|180|U|{2/U}{2/R}{2/G}|Sorcery|||Double the power and toughness of target creature you control until end of turn. Then it fights up to one target creature an opponent controls.| Effortless Master|Tarkir: Dragonstorm|181|U|{2}{U}{R}|Creature - Orc Monk|4|3|Vigilance$Menace$This creature enters with two +1/+1 counters on it if you've cast two or more spells this turn.| Eshki Dragonclaw|Tarkir: Dragonstorm|182|R|{1}{G}{U}{R}|Legendary Creature - Human Warrior|4|4|Vigilance, trample, ward {1}$At the beginning of combat on your turn, if you've cast both a creature spell and a noncreature spell this turn, draw a card and put two +1/+1 counters on Eshki Dragonclaw.| Fangkeeper's Familiar|Tarkir: Dragonstorm|183|R|{1}{B}{G}{U}|Creature - Snake|3|3|Flash$When this creature enters, choose one --$* You gain 3 life and surveil 3.$* Destroy target enchantment.$* Counter target creature spell.| @@ -57364,7 +57404,7 @@ Inevitable Defeat|Tarkir: Dragonstorm|194|R|{1}{R}{W}{B}|Instant|||This spell ca Jeskai Brushmaster|Tarkir: Dragonstorm|195|U|{1}{U}{R}{W}|Creature - Orc Monk|2|4|Double strike$Prowess| Jeskai Revelation|Tarkir: Dragonstorm|196|M|{4}{U}{R}{W}|Instant|||Return target spell or permanent to its owner's hand. Jeskai Revelation deals 4 damage to any target. Create two 1/1 white Monk creature tokens with prowess. Draw two cards. You gain 4 life.| Jeskai Shrinekeeper|Tarkir: Dragonstorm|197|U|{2}{U}{R}{W}|Creature - Dragon|3|3|Flying, haste$Whenever this creature deals combat damage to a player, you gain 1 life and draw a card.| -Karakyk Guardian|Tarkir: Dragonstorm|198|U|{3}{G}{U}{R}|Creature -- Dragon|6|5|Flying, vigilance, trample$This creature has hexproof if it hasn't dealt damage yet.| +Karakyk Guardian|Tarkir: Dragonstorm|198|U|{3}{G}{U}{R}|Creature - Dragon|6|5|Flying, vigilance, trample$This creature has hexproof if it hasn't dealt damage yet.| Kheru Goldkeeper|Tarkir: Dragonstorm|199|U|{1}{B}{G}{U}|Creature - Dragon|3|3|Flying$Whenever one or more cards leave your graveyard during your turn, create a Treasure token.$Renew -- {2}{B}{G}{U}, Exile this card from your graveyard: Put two +1/+1 counters and a flying counter on target creature. Activate only as a sorcery.| Kin-Tree Severance|Tarkir: Dragonstorm|200|U|{2/W}{2/B}{2/G}|Instant|||Exile target permanent with mana value 3 or greater.| Kishla Skimmer|Tarkir: Dragonstorm|201|U|{G}{U}|Creature - Bird Scout|2|2|Flying$Whenever a card leaves your graveyard during your turn, draw a card. This ability triggers only once each turn.| @@ -57384,6 +57424,7 @@ Absorb Essence|Tarkir: Dragonstorm|213|U|{1}{W}|Instant - Omen|4|4|Target creatu Rakshasa's Bargain|Tarkir: Dragonstorm|214|U|{2/B}{2/G}{2/U}|Instant|||Look at the top four cards of your library. Put two of them into your hand and the rest into your graveyard.| Rediscover the Way|Tarkir: Dragonstorm|215|R|{U}{R}{W}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I, II -- Look at the top three cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order.$III -- Whenever you cast a noncreature spell this turn, target creature you control gains double strike until end of turn.| Reigning Victor|Tarkir: Dragonstorm|216|C|{2/R}{2/W}{2/B}|Creature - Orc Warrior|3|3|Mobilize 1$When this creature enters, target creature gets +1/+0 and gains indestructible until end of turn.| +Reputable Merchant|Tarkir: Dragonstorm|217|C|{2/W}{2/B}{2/G}|Creature - Human Citizen|2|2|When this creature enters or dies, put a +1/+1 counter on target creature you control.| Revival of the Ancestors|Tarkir: Dragonstorm|218|R|{1}{W}{B}{G}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I -- Create three 1/1 white Spirit creature tokens.$II -- Distribute three +1/+1 counters among one, two, or three target creatures you control.$III -- Creatures you control gain trample and lifelink until end of turn.| Riverwheel Sweep|Tarkir: Dragonstorm|219|U|{2/U}{2/R}{2/W}|Sorcery|||Tap target creature. Put three stun counters on it.$Exile the top two cards of your library. Choose one of them. Until the end of your next turn, you may play that card.| Roar of Endless Song|Tarkir: Dragonstorm|220|R|{2}{G}{U}{R}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I, II -- Create a 5/5 green Elephant creature token.$III -- Double the power and toughness of each creature you control until end of turn.| @@ -57446,7 +57487,6 @@ Island|Tarkir: Dragonstorm|279|C||Basic Land - Island|||({T}: Add {U}.)| Swamp|Tarkir: Dragonstorm|281|C||Basic Land - Swamp|||({T}: Add {B}.)| Mountain|Tarkir: Dragonstorm|283|C||Basic Land - Mountain|||({T}: Add {R}.)| Forest|Tarkir: Dragonstorm|285|C||Basic Land - Forest|||({T}: Add {G}.)| -Strategic Betrayal|Tarkir: Dragonstorm|422|U|{1}{B}|Sorcery|||Target opponent exiles a creature they control and their graveyard.| Betor, Ancestor's Voice|Tarkir: Dragonstorm Commander|1|M|{2}{W}{B}{G}|Legendary Creature - Spirit Dragon|3|5|Flying, lifelink$At the beginning of your end step, put a number of +1/+1 counters on up to one other target creature you control equal to the amount of life you gained this turn. Return up to one target creature card with mana value less than or equal to the amount of life you lost this turn from your graveyard to the battlefield.| Elsha, Threefold Master|Tarkir: Dragonstorm Commander|2|M|{U}{R}{W}|Legendary Creature - Djinn Monk|1|1|Trample$Prowess$Whenever Elsha deals combat damage to a player, create that many 1/1 white Monk creature tokens with prowess.| Eshki, Temur's Roar|Tarkir: Dragonstorm Commander|3|M|{G}{U}{R}|Legendary Creature - Human Warrior|2|2|Whenever you cast a creature spell, put a +1/+1 counter on Eshki. If that spell's power is 4 or greater, draw a card. If that spell's power is 6 or greater, Eshki deals damage equal to Eshki's power to each opponent.|